home *** CD-ROM | disk | FTP | other *** search
/ Magnum One / Magnum One (Mid-American Digital) (Disc Manufacturing).iso / d12 / emstools.arc / MEMINTRL.C < prev    next >
C/C++ Source or Header  |  1990-02-04  |  126KB  |  2,547 lines

  1. /**********************************************************************/
  2. /*                                                                    */
  3. /*     Module: MEMINTRL.INC                                           */
  4. /*                                                                    */
  5. /*     This module contains the internal routines used by MEMLIB.C.   */
  6. /*     These functions are designed to be called by the functions     */
  7. /*     contained in MEMLIB.C only and are not for use by an           */
  8. /*     application.                                                   */
  9. /*                                                                    */
  10. /**********************************************************************/
  11.  
  12. /*$PAGE*/
  13. /*====================================================================*/
  14. /*   INCLUDE FILES                                                    */
  15. /*====================================================================*/
  16.  
  17. #include <stddef.h>
  18. #include <malloc.h>
  19. #include <dos.h>
  20.  
  21. /*******************************************************************/
  22. /* Error code definitions for MEMLIB.  Since MEMLIB makes calls to */
  23. /* EMMLIB you may get EMM specific errors.  These errors can be    */
  24. /* found in table A-2 in the EMS manual.                           */
  25. /*******************************************************************/
  26.  
  27. #include "errors.h"
  28.  
  29. /********************************/
  30. /* External Function prototypes */
  31. /********************************/
  32.  
  33. #include "memlib.h"
  34. #include "emmlib.h"
  35.  
  36. /********************************/
  37. /* Internal Function prototypes */
  38. /********************************/
  39.  
  40. unsigned int init_exp_mem   (void);
  41. unsigned int break_overlap  (unsigned int *);
  42. unsigned int check_best_fit (unsigned int, unsigned int *, long *);
  43. unsigned int split_block    (unsigned int, unsigned int);
  44. unsigned int search_after   (unsigned int, unsigned int *, unsigned int *);
  45. unsigned int search_before  (unsigned int, unsigned int *, unsigned int *);
  46. unsigned int coalesce_block (unsigned int, unsigned int, unsigned int *);
  47. unsigned int map_dir_page   (unsigned int, unsigned int);
  48. unsigned int check_token    (unsigned int);
  49. unsigned int find_new_dir_start          (void);
  50. unsigned int restore_memlib_context      (unsigned int);
  51. unsigned int allocate_new_directory_page (void);
  52. unsigned int allocate_new_block          (unsigned int, unsigned int);
  53. unsigned int check_if_all_blocks_free    (unsigned int *);
  54. unsigned int prepare_dir_mapping         (unsigned int *);
  55.  
  56. /*$PAGE*/
  57. /*====================================================================*/
  58. /*   DEFINES                                                          */
  59. /*====================================================================*/
  60.  
  61. #define TRUE                       (unsigned int) 1
  62. #define FALSE                      (unsigned int) 0
  63. #define PASSED                     (unsigned int) 0
  64. #define K64K                       (unsigned long) (64L * 1024L)
  65. #define K16K                       (unsigned int) (16 * 1024)
  66.  
  67. #define PAGE_SIZE                  (unsigned int) K16K
  68. #define MAX_PAGE_FRAME_SIZE        (unsigned int) 24
  69. #define LARGEST_ALLOCATABLE_BLOCK  (unsigned int) (K64K - 1)
  70. #define MAX_ALLOCATABLE_PAGES      (unsigned int) 4
  71. #define MAX_CONTEXTS_AVAILABLE     (unsigned int) 10
  72. #define MAX_DIR_ENTRIES            (unsigned int) (K64K - 1)
  73.  
  74. #define FIRST_PHYS_PAGE            (unsigned int) 0
  75. #define SECOND_PHYS_PAGE           (unsigned int) 1
  76.  
  77. #define UNASSIGNED_TOKEN           (unsigned int) 0xFFFF
  78. #define OFFSET_SIZE                (unsigned int) 0x0400
  79. #define UNMAPPED                   (unsigned int) 0xFFFF
  80. #define NO_CONTEXTS                (unsigned int) 0xFFFF
  81.  
  82. #define EMM_NOT_ENOUGH_PAGES       (unsigned int) 0x88
  83.  
  84. #define DIR_ENTRIES_PER_PAGE       (PAGE_SIZE / sizeof(DIRECTORY_NODE))
  85.  
  86. /*$PAGE*/
  87. /*====================================================================*/
  88. /*   TYPEDEFS                                                         */
  89. /*====================================================================*/
  90.  
  91. /**********************************************************************/
  92. /* This structure stores the housekeeping information used to         */
  93. /* uniquely identify a block of memory and to do garbage collection.  */
  94. /* The directory is an array of these structures.                     */
  95. /*                                                                    */
  96. /*  token        - An identifier to a block of memory which is an     */
  97. /*                 index in the directory array.                      */
  98. /*  size         - The size of the memory block.                      */
  99. /*  logical_page - The array of logical pages that the block uses.    */
  100. /*  offset       - The offset into this block's first logical page.   */
  101. /*                 We only need to keep track of the offset since the */
  102. /*                 segment is set by seteptrs when access is desired. */
  103. /*                                                                    */
  104. /* We must keep track of the directory entries in two ways (an entry  */
  105. /* meaning the index into the directory array which gives us access   */
  106. /* to the structure above).  One is in which the token is used as an  */
  107. /* index into the directory array, giving us a range of 0 - 65535     */
  108. /* directory entries.  Second is when we actually want to access a    */
  109. /* directory entry.  Since we cannot map in the entire directory, due */
  110. /* to its size, we must find what logical page an entry belongs to,   */
  111. /* map that page in, and access that entry by using an index into     */
  112. /* that page.  This index has a range of 0 to the number of entries   */
  113. /* possible in a page.                                                */
  114. /*                                                                    */
  115. /* Note: The token has two uses -- one for identifying a block of     */
  116. /* memory and other as an index into the full directory array which   */
  117. /* gives us acces to a DIRECTORY_NODE structure.  The user of MEMLIB  */
  118. /* always keeps track of his blocks of memory with the token value    */
  119. /* and does not have to worry about the directory array.              */
  120. /*                                                                    */
  121. /* In order to know which logical page to map in we use the following */
  122. /* formula:                                                           */
  123. /*                                                                    */
  124. /* directory_log_page = token / DIR_ENTRIES_PER_PAGE                  */
  125. /*                                                                    */
  126. /* Token is the actual entry into the directory that identifies a     */
  127. /* block.  NUM_DIR_ENTRIES is a macro that returns the number of      */
  128. /* directory entries possible in a given number of pages -- in this   */
  129. /* case one page.  By performing an integer divide, we obtain the     */
  130. /* logical page number that this token's directory entry resides in.  */            
  131. /*                                                                    */
  132. /* In order to access a directory entry when it is mapped in we use   */
  133. /* this formula:                                                      */
  134. /*                                                                    */
  135. /* directory_index = token % DIR_ENTRIES_PER_PAGE                     */
  136. /*                                                                    */
  137. /* This number is used as an index into the page of the directory     */
  138. /* array that's mapped in.  This number is different than the token   */
  139. /* which identifies the entry into the full directory array.          */
  140. /**********************************************************************/
  141.  
  142. typedef struct 
  143. {
  144.    unsigned int token;
  145.    unsigned int size;
  146.    unsigned int logical_page [MAX_ALLOCATABLE_PAGES];
  147.    unsigned int offset;
  148.  
  149. } DIRECTORY_NODE;
  150.  
  151. /**********************************************************************/
  152. /* This structure is for holding the segment and page number of a     */
  153. /* mappable memory region.  This will be used in an array to hold the */
  154. /* entire list of mappable memory regions.                            */
  155. /**********************************************************************/
  156.  
  157. typedef struct 
  158. {
  159.    unsigned int phys_page_segment;
  160.    unsigned int phys_page_number;
  161.  
  162. } MAPPABLE_REGIONS;
  163.  
  164.  
  165. /*$PAGE*/
  166. /*====================================================================*/
  167. /*                 MACROS                                             */
  168. /*====================================================================*/
  169.  
  170. /**********************************************************************/
  171. /* This macro returns the number of PAGE_SIZE pages needed for a      */
  172. /* memory block of the given size.                                    */
  173. /**********************************************************************/
  174. #define NUM_PAGES(size) ((unsigned int) (((unsigned long) size + PAGE_SIZE - 1) / PAGE_SIZE))
  175.  
  176. /**********************************************************************/
  177. /* This macro returns the number of directory entries that fit within */
  178. /* the given amount of PAGES_SIZE pages.                              */
  179. /**********************************************************************/
  180. #define NUM_DIR_ENTRIES(num_pages) ((unsigned long) (PAGE_SIZE / sizeof (DIRECTORY_NODE)) * num_pages)
  181.  
  182. /*$PAGE*/
  183. /*====================================================================*/
  184. /*   GLOBAL VARIABLES                                                 */
  185. /*====================================================================*/
  186.  
  187. /**********************************************************************/
  188. /* Actual number of PAGE_SIZE pages available in the page frame       */
  189. /**********************************************************************/
  190.  
  191. unsigned int num_pages_in_page_frame;
  192.  
  193. /**********************************************************************/
  194. /* Store the page frame base address                                  */
  195. /**********************************************************************/
  196.  
  197. void far* page_frame_base_address;
  198.  
  199. /**********************************************************************/
  200. /* Store the EMM handle that the app will use                         */
  201. /* Store the EMM handle that the memory manager will use              */
  202. /**********************************************************************/
  203.  
  204. unsigned int app_handle;
  205. unsigned int man_handle;
  206.  
  207. /**********************************************************************/
  208. /* The first time that any of the external MEMLIB functions are       */
  209. /* called the initializing routine must be called.  This flag is set  */
  210. /* to TRUE once the call is made.                                     */
  211. /**********************************************************************/
  212.  
  213. unsigned int exp_initialized = FALSE;
  214.  
  215. /**********************************************************************/
  216. /* An array of pointers to each pysical page that the directory uses. */
  217. /* When we need to access two different entries on two separate pages */
  218. /* we can map both pages needed in.                                   */
  219. /**********************************************************************/
  220.  
  221. DIRECTORY_NODE far* directory[2];
  222.  
  223. /**********************************************************************/
  224. /* Number of pages for the directory (dynamically changes)            */
  225. /**********************************************************************/
  226.  
  227. unsigned int dir_page_count;
  228.  
  229. /**********************************************************************/
  230. /* Array tells which logical page is mapped at each physical page.    */
  231. /* UNMAPPED ==> no page is mapped.   Unmap 24 pages (A000 - EFFF).    */
  232. /**********************************************************************/
  233.  
  234. MAP_STRUCT pages_mapped[MAX_PAGE_FRAME_SIZE] =
  235.    UNMAPPED,0,  UNMAPPED,1,  UNMAPPED,2,  UNMAPPED,3,
  236.    UNMAPPED,4,  UNMAPPED,5,  UNMAPPED,6,  UNMAPPED,7,
  237.    UNMAPPED,8,  UNMAPPED,9,  UNMAPPED,10, UNMAPPED,11,
  238.    UNMAPPED,12, UNMAPPED,13, UNMAPPED,14, UNMAPPED,15,
  239.    UNMAPPED,16, UNMAPPED,17, UNMAPPED,18, UNMAPPED,19,
  240.    UNMAPPED,20, UNMAPPED,21, UNMAPPED,22, UNMAPPED,23 
  241. };
  242.  
  243. /**********************************************************************/
  244. /* number_pages_mapped stores the number actually mapped.             */
  245. /**********************************************************************/
  246.  
  247. unsigned int number_pages_mapped = 0;
  248.  
  249. /**********************************************************************/
  250. /* The total number of pages allocated to the application.            */
  251. /**********************************************************************/
  252.  
  253. unsigned int total_app_allocated_pages;
  254.  
  255. /**********************************************************************/
  256. /* Used to get and restore partial page maps for push_context() and   */
  257. /* pop_context().                                                     */
  258. /**********************************************************************/
  259.  
  260. PARTIAL_CONTEXT_LIST_STRUCT partial_page_map;
  261.  
  262. /**********************************************************************/
  263. /* An array of pointers to saved contexts used by the push_context()  */
  264. /* and pop_context() functions.                                       */
  265. /**********************************************************************/
  266.  
  267. CONTEXT_STRUCT* context_ptrs[MAX_CONTEXTS_AVAILABLE];
  268.  
  269. /**********************************************************************/
  270. /* This variable keeps track of the top of the context_ptrs array.    */
  271. /* This allows pop_context() to know whether there are any contexts   */
  272. /* left to remove or for push_context() to know whether there is      */
  273. /* enough room to store another context.                              */
  274. /**********************************************************************/
  275.  
  276. unsigned int context_top;     
  277.  
  278. /**********************************************************************/
  279. /* Size of each context - set in init_exp_mem().                      */
  280. /**********************************************************************/
  281.  
  282. unsigned int context_size;
  283.  
  284. /**********************************************************************/
  285. /* The index into the full directory array used as the starting       */
  286. /* location when searching through the directory for a viable entry   */
  287. /* to keep track of a new memory block.                               */
  288. /**********************************************************************/
  289.  
  290. unsigned int dir_start;
  291.  
  292. /**********************************************************************/
  293. /* The index into the full directory array used as the ending         */
  294. /* location when searching through the directory for a viable entry   */
  295. /* to keep track of a new memory block.                               */
  296. /**********************************************************************/
  297.  
  298. unsigned int dir_end;
  299.  
  300. /*$PAGE*/
  301. /*====================================================================*/
  302. /*              CODE                                                  */
  303. /*====================================================================*/
  304.  
  305. /**********************************************************************/
  306. /*     Name:  unsigned int prepare_dir_mapping (context_saved)        */
  307. /*            unsigned int *context_saved;                            */
  308. /*                                                                    */
  309. /*     Definition:                                                    */
  310. /*        To save the context before mapping in the directory.  This  */
  311. /*     function is called before a directory page will be mapped in.  */
  312. /*     It firsts checks to see if the expanded memory has been        */
  313. /*     initialized and then saves the current context.  The status    */
  314. /*     will be returned to the caller for error checking.             */
  315. /*     'context_saved' is set to TRUE if save_context() was           */
  316. /*     successful.                                                    */
  317. /*                                                                    */
  318. /*     The calling function can then call restore_memlib_context()    */
  319. /*     depending whether 'saved' is TRUE or not.  This allows the     */
  320. /*     caller to preserve the error status from save_context().       */
  321. /*                                                                    */
  322. /*     Parameters:                                                    */
  323. /*        output  context_saved  Whether the context was saved or not */
  324. /*                                                                    */
  325. /*     Results returned:                                              */
  326. /*        PASSED     Operation successful                             */
  327. /*        error      Non-zero value, see "ERRORS.H" or EMS table A-2  */
  328. /*                                                                    */
  329. /*     Calls: init_exp_mem()                                          */
  330. /*            save_context()                                          */
  331. /*                                                                    */
  332. /*     Called by: ememavl()                                           */
  333. /*                ememmax()                                           */
  334. /*                emsize()                                            */
  335. /*                efmalloc()                                          */
  336. /*                effree()                                            */
  337. /*                                                                    */
  338. /*     Globals referenced/modified: exp_initialized                   */
  339. /*                                  man_handle                        */
  340. /*                                                                    */
  341. /**********************************************************************/
  342.  
  343. unsigned int prepare_dir_mapping (context_saved)
  344. unsigned int *context_saved;
  345. {
  346.    unsigned int status;          /* The status of EMM and MEMLIB */
  347.                                                                   
  348.    *context_saved = FALSE;
  349.    status         = PASSED;
  350.  
  351.    /**********************************************/
  352.    /* If expanded memory hasn't been initialized */
  353.    /* then call init_exp_mem().                  */
  354.    /**********************************************/
  355.  
  356.    if (!exp_initialized)
  357.       status = init_exp_mem();
  358.  
  359.    if (status == PASSED)
  360.    {
  361.       /*****************************/
  362.       /* Save the current context. */
  363.       /*****************************/
  364.  
  365.       status = save_context (man_handle);
  366.       if (status == PASSED)
  367.       {
  368.          *context_saved = TRUE;
  369.       }
  370.    }
  371.    return (status);
  372.  
  373. } /** prepare_dir_mapping **/
  374.  
  375. /*$PAGE*/
  376. /**********************************************************************/
  377. /*     Name:  unsigned int map_dir_page (log_page, phys_page)         */
  378. /*            unsigned int log_page;                                  */
  379. /*            unsigned int phys_page;                                 */
  380. /*                                                                    */
  381. /*     Definition:                                                    */
  382. /*        Maps in the specified logical page for the directory into   */
  383. /*     the specified physical page.  For use by MEMLIB only (uses     */
  384. /*     MEMLIB handle -- man_handle).                                  */
  385. /*                                                                    */
  386. /*     Parameters:                                                    */
  387. /*        input   log_page    The logical directory page to map in    */
  388. /*        input   phys_page   Which physical page to map log_page in  */
  389. /*                                                                    */
  390. /*     Results returned:                                              */
  391. /*        PASSED     Operation successful                             */
  392. /*        error      Non-zero value, see "ERRORS.H" or EMS table A-2  */
  393. /*                                                                    */
  394. /*     Calls: map_unmap_pages()                                       */
  395. /*                                                                    */
  396. /*     Called by: ememavl()                                           */
  397. /*                ememmax()                                           */
  398. /*                emsize()                                            */
  399. /*                efmalloc()                                          */
  400. /*                effree()                                            */
  401. /*                seteptrs()                                          */
  402. /*                                                                    */
  403. /*     Globals referenced/modified: exp_intialized                    */
  404. /*                                  man_handle                        */
  405. /*                                                                    */
  406. /**********************************************************************/
  407.  
  408. unsigned int map_dir_page (log_page, phys_page)
  409. unsigned int log_page;
  410. unsigned int phys_page;
  411. {
  412.    MAP_STRUCT   directory_map[1];  /* Structure to use EMS map pages */
  413.    unsigned int status;            /* Status of EMM and MEMLIB       */
  414.  
  415.    directory_map[0].log_page         = log_page;
  416.    directory_map[0].phys_page_or_seg = phys_page;
  417.    status = map_unmap_pages (PHYS_PAGE_MODE, 1, directory_map, man_handle);
  418.  
  419.    return (status);
  420. } /** end map_dir_page **/
  421.  
  422. /*$PAGE*/
  423. /**********************************************************************/
  424. /*                                                                    */
  425. /*     Name:    unsigned int restore_memlib_context (status)          */
  426. /*              unsigned int status;                                  */
  427. /*                                                                    */
  428. /*     Description:                                                   */
  429. /*        Restores a context saved by prepare_dir_mapping() so that   */
  430. /*     memlib can access the directory.  If the status passed in is   */
  431. /*     an error, then that is the status returned regardless if       */
  432. /*     restore_context() generates an error.  If the status passed in */
  433. /*     is PASSED, we return the status generated by restore_context().*/
  434. /*        We do this so that in some recoverable errors we can        */
  435. /*     successfully restore the context and still return the correct  */
  436. /*     error code to the application.                                 */
  437. /*                                                                    */
  438. /*     Parameters:                                                    */
  439. /*        input   status     The status passed in                     */
  440. /*                                                                    */
  441. /*     Results returned:                                              */
  442. /*        PASSED     Operation successful                             */
  443. /*        error      Non-zero value, see "ERRORS.H" or EMS table A-2  */
  444. /*                                                                    */
  445. /*     Calls: restore_context()                                       */
  446. /*                                                                    */
  447. /*     Called by: ememavl()                                           */
  448. /*                ememmax()                                           */
  449. /*                emsize()                                            */
  450. /*                efmalloc()                                          */
  451. /*                effree()                                            */
  452. /*                                                                    */
  453. /*     Globals referenced/modified: man_handle                        */
  454. /*                                                                    */
  455. /**********************************************************************/
  456.  
  457. unsigned int restore_memlib_context (status)
  458. unsigned int status;
  459. {
  460.    unsigned int restore_status;  /* Status returned from restore_context */
  461.  
  462.    restore_status = restore_context (man_handle);
  463.    if (status == PASSED)
  464.       return (restore_status);
  465.    else
  466.       return (status);
  467.  
  468. } /** end restore_memlib_context **/
  469.      
  470. /*$PAGE*/
  471. /**********************************************************************/
  472. /*                                                                    */
  473. /*     Name:  unsigned int check_token (token)                        */
  474. /*            unsigned int token;                                     */
  475. /*                                                                    */
  476. /*     Description:                                                   */
  477. /*        This function check's a token to see if it is valid.  It    */
  478. /*     is valid if it is within the directory boundries.  A token is  */
  479. /*     valid when it is set by efmalloc().                            */
  480. /*                                                                    */
  481. /*     Parameters:                                                    */
  482. /*        input    token   The token to be validated.                 */
  483. /*                                                                    */
  484. /*     Results returned:                                              */
  485. /*        PASSED     Operation successful                             */
  486. /*        error      Non-zero value, see "ERRORS.H" or EMS table A-2  */
  487. /*                                                                    */
  488. /*     Calls: None                                                    */
  489. /*                                                                    */
  490. /*     Called by: effree()                                            */
  491. /*                emsize()                                            */
  492. /*                                                                    */
  493. /*     Globals referenced/modified: dir_page_count                    */
  494. /*                                  exp_initialized                   */
  495. /*                                                                    */
  496. /**********************************************************************/
  497.  
  498. unsigned int check_token (token)
  499. unsigned int token;
  500. {
  501.    unsigned int status;          /* The status of EMM and MEMLIB */
  502.  
  503.    /******************/
  504.    /* Assume PASSED. */
  505.    /******************/
  506.  
  507.    status = PASSED;
  508.  
  509.    /****************************************************************/
  510.    /* If the manager is not initialized then the token is invalid. */
  511.    /****************************************************************/
  512.  
  513.    if (!exp_initialized)
  514.       status = INVALID_TOKEN;
  515.  
  516.    /***************************************************************/
  517.    /* First make sure the token isn't greater than the number of  */
  518.    /* entries possible for the current number of directory pages. */
  519.    /* Then check for a valid token.                               */
  520.    /***************************************************************/
  521.  
  522.    if (status == PASSED)
  523.    {
  524.       if ((token > (unsigned int) (NUM_DIR_ENTRIES (dir_page_count) - 1)) ||
  525.           (token == UNASSIGNED_TOKEN))
  526.          status = INVALID_TOKEN;
  527.    }
  528.  
  529.    return(status);
  530.  
  531. } /** end check_token **/
  532.  
  533. /*$PAGE*/
  534. /**********************************************************************/
  535. /*                                                                    */
  536. /*     Name:     unsigned int init_exp_mem (void)                     */
  537. /*                                                                    */
  538. /*     Description:                                                   */
  539. /*        This routine initializes the housekeeping variables needed  */
  540. /*     to keep track of expanded memory.  It tests for the presence   */
  541. /*     of EMM 4.0 and initializes the directory.                      */
  542. /*                                                                    */
  543. /*     Parameters: None                                               */
  544. /*                                                                    */
  545. /*     Results returned:                                              */
  546. /*        PASSED     Operation successful                             */
  547. /*        error      Non-zero value, see "ERRORS.H" or EMS table A-2  */
  548. /*                                                                    */
  549. /*     Calls: alloc_pages()                                           */
  550. /*            EMM_installed()                                         */
  551. /*            get_page_frame_seg()                                    */
  552. /*            get_partial_context_size()                              */
  553. /*            get_unalloc_page_count()                                */
  554. /*            realloc_pages()                                         */
  555. /*            map_dir_page()                                          */
  556. /*            get_page_frame_count()                                  */
  557. /*                                                                    */
  558. /*     Called by: prepare_dir_mapping()                               */
  559. /*                push_context()                                      */
  560. /*                pop_context()                                       */
  561. /*                                                                    */
  562. /*     Globals referenced/modified: directory                         */  
  563. /*                                  app_handle                        */
  564. /*                                  context_size                      */
  565. /*                                  dir_page_count                    */
  566. /*                                  exp_intialized                    */
  567. /*                                  man_handle                        */
  568. /*                                  number_pages_mapped               */
  569. /*                                  page_frame_base_address           */
  570. /*                                  num_pages_in_page_frame           */
  571. /*                                  pages_mapped                      */
  572. /*                                  context_top                       */
  573. /*                                  total_app_allocated_pages         */
  574. /*                                  dir_start                         */
  575. /*                                  dir_end                           */
  576. /*                                  exp_initialized                   */
  577. /*                                  partial_page_map                  */
  578. /*                                                                    */
  579. /**********************************************************************/
  580.  
  581. unsigned int init_exp_mem (void)
  582. {
  583.  
  584.    unsigned int status;            /* The status of EMM and MEMLIB */
  585.    unsigned int num_unalloc_pages; /* Number of unallocated pages  */
  586.    unsigned int page_frame_seg;    /* Page frame segment           */
  587.    unsigned int i;                 /* Looping variable             */
  588.    unsigned int zero_pages;        /* To call realloc for 0 pages  */
  589.  
  590.    /********************************************************/
  591.    /* Test for EMM presence and enough pages -- need at    */
  592.    /* least 1 for the directory and 1 for the application. */
  593.    /********************************************************/
  594.  
  595.    status = EMM_installed();
  596.    if (status == PASSED)
  597.    {
  598.       status = get_unalloc_page_count (&num_unalloc_pages);
  599.       if (status == PASSED)
  600.          if (num_unalloc_pages <= 1)
  601.             status = NOT_ENOUGH_UNALLOCATED_PAGES;
  602.    }
  603.  
  604.    if (status == PASSED)
  605.    {
  606.       /*****************************************/
  607.       /* Allocate 0 pages for the application. */
  608.       /* We need to first alloc 1 page to get  */
  609.       /* a handle then realloc to reduce the   */
  610.       /* number of pages used to 0.            */
  611.       /*****************************************/
  612.  
  613.       status = alloc_pages (1, &app_handle);
  614.       if (status == PASSED)
  615.          {
  616.          zero_pages = 0;
  617.          status = realloc_pages (&zero_pages, app_handle);
  618.          if ((zero_pages != 0) ||
  619.              (status == EMM_NOT_ENOUGH_PAGES))
  620.             status = NOT_ENOUGH_UNALLOCATED_PAGES;
  621.          }
  622.  
  623.       /*********************************************/
  624.       /* Allocate 1 page for the manager (memlib). */
  625.       /*********************************************/
  626.  
  627.       if (status == PASSED)
  628.          status = alloc_pages (1, &man_handle);
  629.  
  630.       if (status == PASSED)
  631.       {
  632.          /****************************/
  633.          /* Map this directory page. */
  634.          /****************************/
  635.  
  636.          status = map_dir_page (0, FIRST_PHYS_PAGE);
  637.       }
  638.  
  639.       if (status == PASSED)
  640.       {
  641.          /*********************************************************/
  642.          /* Get the base address of the start of expanded memory. */
  643.          /*********************************************************/
  644.  
  645.          status = get_page_frame_seg (&page_frame_seg);
  646.          if (status == PASSED)
  647.          {
  648.             /***************************************************/
  649.             /* Convert the page frame segment to a far pointer */
  650.             /* and point directory[0] to it.                   */
  651.             /***************************************************/
  652.  
  653.             page_frame_base_address = FP (page_frame_seg);
  654.             directory[0] = (DIRECTORY_NODE far *) page_frame_base_address;
  655.  
  656.             /****************************************************/
  657.             /* Point directory[1] to the address of the second  */
  658.             /* physical page in the page frame.                 */
  659.             /****************************************************/
  660.             FP_SEG(directory[1]) = page_frame_seg + OFFSET_SIZE;
  661.             FP_OFF(directory[1]) = 0;
  662.          }
  663.       }
  664.    }
  665.  
  666.    if (status == PASSED)
  667.    {
  668.       /************************************************/
  669.       /* Set the variable that keeps track of the how */
  670.       /* many pages the directory is using to 1.      */
  671.       /************************************************/
  672.  
  673.       dir_page_count = 1;
  674.  
  675.       /**************************************************************/
  676.       /* Initialize all the directory entries so that the token     */
  677.       /* identifiers are set UNASSIGNED_TOKEN (entry is available)  */
  678.       /* and their size to 0.                                       */
  679.       /**************************************************************/
  680.  
  681.       for (i = 0; i < DIR_ENTRIES_PER_PAGE; i++)
  682.       {
  683.          directory[0][i].token = UNASSIGNED_TOKEN;
  684.          directory[0][i].size = 0;
  685.       }
  686.  
  687.       /********************************************************/
  688.       /* Set the starting and ending entries in the directory */
  689.       /* when doing free memory block searches.               */
  690.       /********************************************************/
  691.  
  692.       dir_start = 0;
  693.       dir_end   = 0;
  694.  
  695.       /****************************************************************/
  696.       /* Set the total number of pages the application is using to 0. */
  697.       /****************************************************************/
  698.  
  699.       total_app_allocated_pages = 0;
  700.  
  701.       /**********************************************/
  702.       /* Get the number of pages in the page frame. */
  703.       /**********************************************/
  704.  
  705.       status = get_page_frame_count (&num_pages_in_page_frame);
  706.  
  707.       if (status == PASSED)
  708.       {
  709.          /*************************************************/
  710.          /* Set the partial page map for pushes and pops. */
  711.          /*************************************************/
  712.  
  713.          partial_page_map.mappable_region_count = num_pages_in_page_frame;
  714.          partial_page_map.mappable_region_seg[0] = FP_SEG (page_frame_base_address);
  715.  
  716.          /*************************************************************/
  717.          /* Set the segment value for each 16K page in the page frame */
  718.          /* that push_context() & pop_context() will be storing.      */
  719.          /*************************************************************/
  720.  
  721.          for (i = 1; i < num_pages_in_page_frame; i++)
  722.          {
  723.             partial_page_map.mappable_region_seg[i] =
  724.                partial_page_map.mappable_region_seg[i - 1] + OFFSET_SIZE;
  725.          }
  726.  
  727.          /***************************************************/
  728.          /* Set the context push and pop stack to be empty. */
  729.          /***************************************************/
  730.  
  731.          context_top = NO_CONTEXTS;
  732.  
  733.          /************************************************************/
  734.          /* Get the number of bytes needed to save (push) a context. */
  735.          /************************************************************/
  736.  
  737.          status = get_partial_context_size (num_pages_in_page_frame, &context_size);
  738.          if (status == PASSED)
  739.          {
  740.             /********************/
  741.             /* Unmap all pages. */
  742.             /********************/
  743.  
  744.             for (i = 0; i < num_pages_in_page_frame; i++)
  745.             {
  746.                pages_mapped[i].log_page = UNMAPPED;
  747.             }
  748.          }
  749.          number_pages_mapped = 0;
  750.       }
  751.    }
  752.    /***************************************************************/
  753.    /* If status is good then update the already-initialized flag. */
  754.    /***************************************************************/
  755.  
  756.    if (status == PASSED)
  757.       exp_initialized = TRUE;
  758.  
  759.    return (status);
  760.  
  761. } /** end init_exp_mem **/
  762.  
  763. /*$PAGE*/
  764. /**********************************************************************/
  765. /*                                                                    */
  766. /*     Name: unsigned int allocate_new_directory_page (void)          */
  767. /*                                                                    */
  768. /*     Description:                                                   */
  769. /*        This routine attempts to allocate a new page for the        */
  770. /*     directory.                                                     */
  771. /*                                                                    */
  772. /*     Parameters:  None                                              */
  773. /*                                                                    */
  774. /*     Results returned:                                              */
  775. /*        PASSED    Operation successful                              */
  776. /*        error     Non-zero value, see "ERRORS.H" or EMS table A-2   */
  777. /*                                                                    */
  778. /*     Calls: map_dir_page()                                          */
  779. /*            realloc_pages()                                         */
  780. /*                                                                    */
  781. /*     Called by: allocate_new_block()                                */
  782. /*                check_best_fit()                                    */
  783. /*                                                                    */
  784. /*     Globals referenced/modified: directory                         */
  785. /*                                  dir_page_count                    */
  786. /*                                  man_handle                        */
  787. /*                                                                    */
  788. /**********************************************************************/
  789.  
  790. unsigned int allocate_new_directory_page (void)
  791. {
  792.    unsigned int status;            /* The status of EMM and MEMLIB  */
  793.    unsigned int index;             /* Index into a directory page   */
  794.    unsigned int new_num_dir_pages; /* New number of directory pages */
  795.  
  796.    /*****************************/
  797.    /* Assume status will be ok. */
  798.    /*****************************/
  799.  
  800.    status = PASSED;
  801.  
  802.    /******************************************/
  803.    /* Set the new number of directory pages. */
  804.    /******************************************/
  805.  
  806.    new_num_dir_pages = dir_page_count + 1;
  807.  
  808.    /***************************************************/
  809.    /* Make sure we don't allocate beyond the maximum  */
  810.    /* number of directory entries allowable.          */
  811.    /***************************************************/
  812.  
  813.    if ((unsigned long) NUM_DIR_ENTRIES (new_num_dir_pages) > MAX_DIR_ENTRIES)
  814.       status = TOO_MANY_DIRECTORY_ENTRIES;
  815.  
  816.    if (status == PASSED)
  817.    {
  818.       /************************************************/
  819.       /* Attempt to add a new page for the directory. */
  820.       /************************************************/
  821.  
  822.       status = realloc_pages (&new_num_dir_pages, man_handle);
  823.  
  824.       /******************************************/
  825.       /* Make sure the number of pages returned */
  826.       /* is equal to the number we wanted.      */
  827.       /******************************************/
  828.  
  829.       if ((status == EMM_NOT_ENOUGH_PAGES) ||
  830.           (new_num_dir_pages != dir_page_count + 1))
  831.          status = NOT_ENOUGH_UNALLOCATED_PAGES;
  832.  
  833.       if (status == PASSED)
  834.       {
  835.          /************************************************/
  836.          /* Allocate succeeded, update the directory map */
  837.          /************************************************/
  838.  
  839.          dir_page_count++;
  840.  
  841.          status = map_dir_page (dir_page_count - 1, FIRST_PHYS_PAGE);
  842.          if (status == PASSED)
  843.          {
  844.             /*****************************************/
  845.             /* Initialize the new directory entries. */
  846.             /*****************************************/
  847.  
  848.             for (index = 0; index < DIR_ENTRIES_PER_PAGE; index++)
  849.             {
  850.                directory[0][index].token = UNASSIGNED_TOKEN;
  851.                directory[0][index].size = 0;
  852.             }
  853.          }
  854.       }
  855.    }
  856.    return (status);
  857.  
  858. }  /** end allocate_new_directory_page **/
  859.  
  860. /*$PAGE*/
  861. /**********************************************************************/
  862. /*                                                                    */
  863. /*     Name: unsigned int allocate_new_block (size, token)            */                                   
  864. /*           unsigned int size;                                       */
  865. /*           unsigned int token;                                      */   
  866. /*                                                                    */
  867. /*     Description:                                                   */
  868. /*        This routine attempts to allocate a block of size 'size',   */
  869. /*     in bytes, and set the fields in directory[token] appropriately.*/
  870. /*                                                                    */
  871. /*     Parameters:                                                    */
  872. /*        input size     the size, in bytes, to allocate              */
  873. /*        input token    index into directory for this block          */
  874. /*                                                                    */
  875. /*     Results returned:                                              */
  876. /*        PASSED    Operation successful                              */
  877. /*        error     Non-zero value, see "ERRORS.H" or EMS table A-2   */
  878. /*                                                                    */
  879. /*     Calls: allocate_new_directory_page()                           */
  880. /*            realloc_pages()                                         */
  881. /*            map_dir_page()                                          */
  882. /*                                                                    */
  883. /*     Called by: efmalloc()                                          */
  884. /*                                                                    */
  885. /*     Globals referenced/modified: directory                         */
  886. /*                                  app_handle                        */
  887. /*                                  dir_page_count                    */
  888. /*                                  total_app_allocated_pages         */
  889. /*                                  dir_start                         */
  890. /*                                  dir_end                           */
  891. /*                                                                    */
  892. /**********************************************************************/
  893.  
  894. unsigned int allocate_new_block (size, token)
  895. unsigned int size;
  896. unsigned int token;
  897. {
  898.    unsigned int i;                  /* Looping variable                    */
  899.    unsigned int page;               /* Current directory page mapped in    */
  900.    unsigned int status;             /* Status of EMM and MEMLIB            */
  901.    unsigned int num_pages_needed;   /* Number of pages needed              */
  902.    unsigned int size_mod_page_size; /* Size in bytes MOD PAGE_SIZE         */
  903.    unsigned int new_total_pages;    /* New number of pages for the         */
  904.                                     /* application's handle                */
  905.    unsigned int tokens_page;        /* Token's dir entry's logical page    */
  906.    unsigned int tokens_index;       /* Token's index into its page         */
  907.    unsigned int i_dir_entry;        /* Translate i to an entry into the    */
  908.                                     /* full directory array                */
  909.    unsigned int dir_starts_page;    /* Dir_start's dir entry's log page    */
  910.    unsigned int dir_starts_index;   /* Dir_start's index into its page     */
  911.    unsigned int found_block;        /* Whether a block was found or not    */
  912.    unsigned int remainders_logical_page; /* The remaining portion's first  */
  913.                                          /* logical page                   */
  914.    
  915.    status = PASSED;
  916.  
  917.    /****************************************************************/
  918.    /* Check if we need to allocate another page for the directory. */
  919.    /****************************************************************/
  920.  
  921.    if (dir_end >= (unsigned int) (NUM_DIR_ENTRIES (dir_page_count) - 2))
  922.       status = allocate_new_directory_page();
  923.  
  924.    if (status == PASSED)
  925.    {
  926.       /********************************************/
  927.       /* Allocate enough new pages for this block */
  928.       /********************************************/
  929.  
  930.       num_pages_needed = NUM_PAGES (size);
  931.       new_total_pages = total_app_allocated_pages + num_pages_needed;
  932.  
  933.       /*************************************************************/
  934.       /* Assign the new number of pages to the application handle. */
  935.       /*************************************************************/
  936.  
  937.       status = realloc_pages (&new_total_pages, app_handle);
  938.  
  939.       /******************************************/
  940.       /* Make sure the number of pages returned */
  941.       /* is equal to the number we wanted.      */
  942.       /******************************************/
  943.  
  944.       if ((new_total_pages != (total_app_allocated_pages + num_pages_needed)) 
  945.           || (status == EMM_NOT_ENOUGH_PAGES))
  946.          status = NOT_ENOUGH_UNALLOCATED_PAGES;
  947.    }
  948.  
  949.    /****************************************************/
  950.    /* If allocate succeeded, set the directory entries */
  951.    /****************************************************/
  952.  
  953.    if (status == PASSED)
  954.    {
  955.       /*******************************************************/
  956.       /* Convert 'token' to its respective directory entry's */
  957.       /* logical page and its index into that page.          */
  958.       /*******************************************************/
  959.  
  960.       tokens_page  = token / DIR_ENTRIES_PER_PAGE;
  961.       tokens_index = token % DIR_ENTRIES_PER_PAGE;
  962.  
  963.       /**************************************/
  964.       /* Map in the token's directory page. */
  965.       /**************************************/
  966.  
  967.       status = map_dir_page (tokens_page, FIRST_PHYS_PAGE);
  968.       if (status == PASSED)
  969.       {
  970.          /**************************************/
  971.          /* Set the entry in the directory for */
  972.          /* the newly allocated block.         */
  973.          /**************************************/
  974.  
  975.          directory[0][tokens_index].token  = token;
  976.          directory[0][tokens_index].size   = size;
  977.          directory[0][tokens_index].offset = 0;
  978.  
  979.          /*********************************************/
  980.          /* Set the logical pages for this block to   */
  981.          /* the logical pages that we just allocated. */
  982.          /*********************************************/
  983.  
  984.          for (i = 0; i < num_pages_needed; i++)
  985.          {
  986.             directory[0][tokens_index].logical_page[i] = 
  987.                total_app_allocated_pages + i;
  988.          }
  989.  
  990.          /**************************************************/
  991.          /* If this block size is NOT a multiple of 16K,   */
  992.          /* find an unused directory entry and have it     */
  993.          /* point to the remaining part of the page.       */
  994.          /**************************************************/
  995.      
  996.          size_mod_page_size = size % PAGE_SIZE;
  997.    
  998.          if (size_mod_page_size != 0)
  999.          {
  1000.             /********************************************************/
  1001.             /* We have a remainder on the last logical page for the */
  1002.             /* new block.  Keep track of this page so that when we  */
  1003.             /* set a free directory entry to point to the remainder */
  1004.             /* we already know what logical page it uses.           */
  1005.             /********************************************************/
  1006.  
  1007.             remainders_logical_page = 
  1008.                directory[0][tokens_index].logical_page[num_pages_needed - 1];
  1009.  
  1010.             dir_starts_page  = dir_start / DIR_ENTRIES_PER_PAGE;
  1011.             dir_starts_index = dir_start % DIR_ENTRIES_PER_PAGE;
  1012.             found_block = FALSE;
  1013.  
  1014.             /****************************************/
  1015.             /* Go through the directory, page by    */
  1016.             /* page, until we find an usable entry. */
  1017.             /****************************************/
  1018.  
  1019.             for (page = dir_starts_page; ((status == PASSED) &&
  1020.                                           (page < dir_page_count) &&
  1021.                                           (!found_block)); page++)
  1022.             {
  1023.                /***********************************/
  1024.                /* Map in the this directory page. */
  1025.                /***********************************/
  1026.  
  1027.                status = map_dir_page (page, FIRST_PHYS_PAGE);
  1028.  
  1029.                /*********************************************************/
  1030.                /* Go through each entry for the mapped in page until we */
  1031.                /* find a usable entry or until we run out of entries.   */
  1032.                /*********************************************************/
  1033.  
  1034.                for (i = dir_starts_index; ((i < DIR_ENTRIES_PER_PAGE) &&
  1035.                                             (!found_block) &&
  1036.                                             (status == PASSED)); i++)
  1037.                {
  1038.                   if ((directory[0][i].token == UNASSIGNED_TOKEN) && 
  1039.                       (directory[0][i].size == 0))
  1040.                   {
  1041.                      /*******************************************/
  1042.                      /* We found an unused directory entry, set */
  1043.                      /* it to point to the leftover piece.      */
  1044.                      /*******************************************/
  1045.  
  1046.                      directory[0][i].offset = size_mod_page_size;
  1047.                      directory[0][i].size = PAGE_SIZE - size_mod_page_size;
  1048.                      directory[0][i].logical_page[0] = remainders_logical_page;
  1049.  
  1050.                      i_dir_entry = page * DIR_ENTRIES_PER_PAGE + i;
  1051.                      if (i_dir_entry >= dir_end)
  1052.                         dir_end = i_dir_entry + 1;
  1053.  
  1054.                      found_block = TRUE;
  1055.                   }
  1056.                } /** end for i **/
  1057.  
  1058.                dir_starts_index = 0;
  1059.  
  1060.             } /** end for page **/
  1061.  
  1062.          } /** end if page_mod_page_size **/
  1063.  
  1064.          /***********************************/
  1065.          /* Update the toal allocated pages */
  1066.          /***********************************/
  1067.  
  1068.          total_app_allocated_pages += num_pages_needed;
  1069.  
  1070.       }  /** end if status PASSED **/
  1071.  
  1072.    } /** end if status PASSED **/
  1073.    return (status);
  1074.  
  1075. }  /** end allocate_new_block **/
  1076.  
  1077.  
  1078. /*$PAGE*/
  1079. /**********************************************************************/
  1080. /*                                                                    */
  1081. /*     Name: unsigned int split_block (best_index, size)              */
  1082. /*           unsigned int best_index;                                 */
  1083. /*           unsigned int size;                                       */
  1084. /*                                                                    */
  1085. /*     Description:                                                   */
  1086. /*        This routine splits a block into allocated and unallocated  */
  1087. /*     portions.  The size is assigned to the allocated portion and   */
  1088. /*     the left over portion is set up as a free block.               */
  1089. /*                                                                    */
  1090. /*     Parms Passed:                                                  */
  1091. /*        input best_index   The directory entry to be broken up.     */
  1092. /*                           It will be the entry that will point to  */
  1093. /*                           the allocated portion after it is broken */
  1094. /*                           into its allocated/free portions.        */
  1095. /*              size         The size of the block to be allocated.   */
  1096. /*                                                                    */
  1097. /*     Results returned:                                              */
  1098. /*        PASSED    Operation successful                              */
  1099. /*        error     Non-zero value, see "ERRORS.H" or EMS table A-2   */
  1100. /*                                                                    */
  1101. /*     Calls: map_dir_page()                                          */
  1102. /*            break_overlap()                                         */
  1103. /*                                                                    */
  1104. /*     Called by:  efmalloc()                                         */
  1105. /*                                                                    */
  1106. /*     Globals referenced/modified: directory                         */
  1107. /*                                  dir_page_count                    */
  1108. /*                                  dir_end                           */
  1109. /*                                  dir_start                         */
  1110. /*                                                                    */
  1111. /**********************************************************************/
  1112.  
  1113. unsigned int split_block (best_index, size)
  1114. unsigned int best_index;
  1115. unsigned int size;
  1116. {
  1117.    unsigned int num_pages_for_size; /* The num of logical pages for size  */
  1118.    unsigned int size_mod_page_size; /* The size modulo the PAGE_SIZE      */
  1119.    unsigned int dir_starts_page;    /* Dir_start's dir entry's log page   */
  1120.    unsigned int best_indexs_page;   /* Best_index's dir entry's log page  */               
  1121.    unsigned int best_indexs_index;  /* Best_index's index into its page   */
  1122.    unsigned int best_index_offset;  /* Best_index's logical page offset   */
  1123.    unsigned int best_index_size;    /* Best_index's memory block's size   */
  1124.    unsigned int index;              /* Current index into a logical page  */
  1125.    unsigned int page;               /* Current directory page mapped in   */
  1126.    unsigned int remainder;          /* The index into a dir page that     */
  1127.                                     /* will point to the leftover portion */
  1128.                                     /* in a logical page after allocated  */
  1129.                                     /* block is set                       */
  1130.    unsigned int remainders_entry;   /* Remainder converted to a full      */
  1131.                                     /* directory entry                    */
  1132.    unsigned int status;             /* Status of EMM and MEMLIB           */
  1133.    unsigned int j;                  /* Looping variable                   */
  1134.    unsigned int avail_entry_found;  /* An available entry has been found  */
  1135.    unsigned int start_page_for_remainder; /* The starting logical page    */
  1136.                                           /* for the remainder            */
  1137.  
  1138.    /*******************************/
  1139.    /* Initialize local variables. */
  1140.    /*******************************/
  1141.  
  1142.    avail_entry_found = FALSE;
  1143.    status            = PASSED;
  1144.  
  1145.    /*************************************************/
  1146.    /* Convert dir_start to its respective directory */
  1147.    /* entry's logcal page.                          */
  1148.    /*************************************************/
  1149.  
  1150.    dir_starts_page  = dir_start / DIR_ENTRIES_PER_PAGE;
  1151.  
  1152.    /**************************************************/
  1153.    /* Convert dir_start to its respective entry's    */
  1154.    /* page index.  We want to start the first        */
  1155.    /* page's index at the current starting location. */                                 
  1156.    /**************************************************/
  1157.  
  1158.    index = dir_start % DIR_ENTRIES_PER_PAGE;
  1159.  
  1160.    /****************************************************************/
  1161.    /* Check if we need to allocate another page for the directory. */
  1162.    /****************************************************************/
  1163.  
  1164.    if (dir_end >= (unsigned int) (NUM_DIR_ENTRIES (dir_page_count) - 2))
  1165.       status = allocate_new_directory_page();
  1166.  
  1167.    /****************************************************************/
  1168.    /* Go through all the directory pages starting with dir_start's */
  1169.    /* page until we find an usable entry.                          */
  1170.    /****************************************************************/
  1171.  
  1172.    for (page = dir_starts_page; ((page < dir_page_count) && 
  1173.                                  (!avail_entry_found) && 
  1174.                                  (status == PASSED)); page++)
  1175.    {
  1176.       /*******************************/
  1177.       /* Map in this directory page. */
  1178.       /*******************************/
  1179.  
  1180.       status = map_dir_page (page, FIRST_PHYS_PAGE);
  1181.       /************************************************************/
  1182.       /* Go through this page's indexes looking for the first     */
  1183.       /* available directory entry to keep track of the remainder */
  1184.       /* portion.  The first time we enter this loop we start     */
  1185.       /* with the current starting location (dir_start converted  */
  1186.       /* to a page's index) from above.  All other index's after  */
  1187.       /* the first page will start with 0.                        */
  1188.       /************************************************************/
  1189.  
  1190.       for (remainder = index; ((remainder < DIR_ENTRIES_PER_PAGE) && 
  1191.                                (!avail_entry_found) &&
  1192.                                (status == PASSED)); remainder++)
  1193.       {
  1194.          if ((directory[0][remainder].size == 0) &&
  1195.              (directory[0][remainder].token == UNASSIGNED_TOKEN))
  1196.          {
  1197.             /**********************************************/
  1198.             /* We've found an available directory entry   */
  1199.             /* to keep track of the left-over portion.    */
  1200.             /* Time to map in the block we want to split. */
  1201.             /**********************************************/
  1202.  
  1203.             avail_entry_found = TRUE;
  1204.  
  1205.             /*******************************************************/
  1206.             /* We're going to map in two different directory pages */
  1207.             /* so that we can reference best_index's and           */
  1208.             /* remainder's directory entry at once.  Since we are  */
  1209.             /* using two different logical pages we need to use    */
  1210.             /* directory[1] to access the second page's entries.   */
  1211.             /*******************************************************/
  1212.  
  1213.             best_indexs_page  = best_index / DIR_ENTRIES_PER_PAGE;
  1214.             best_indexs_index = best_index % DIR_ENTRIES_PER_PAGE;
  1215.  
  1216.             /************************************************/
  1217.             /* Map in the best_index's directory page in at */
  1218.             /* physical page one while keeping  remainder's */
  1219.             /* directory page at physical page zero.        */
  1220.             /************************************************/
  1221.  
  1222.             status = map_dir_page (best_indexs_page, SECOND_PHYS_PAGE);
  1223.             if (status == PASSED)
  1224.             {
  1225.                /*****************************/
  1226.                /* Set some local variables. */
  1227.                /*****************************/
  1228.  
  1229.                best_index_offset  = directory[1][best_indexs_index].offset;
  1230.                best_index_size    = directory[1][best_indexs_index].size;
  1231.                num_pages_for_size = NUM_PAGES (size);
  1232.  
  1233.                /*************************************************/
  1234.                /* Split this block into used and free portions. */
  1235.                /*************************************************/
  1236.  
  1237.                directory[0][remainder].size = best_index_size - size;
  1238.  
  1239.                /***********************************************************/
  1240.                /* Find the starting logical page for the remainder block. */
  1241.                /***********************************************************/
  1242.  
  1243.                if (((best_index_offset + size) % (PAGE_SIZE)) == 0)
  1244.                   start_page_for_remainder = num_pages_for_size;
  1245.                else
  1246.                   start_page_for_remainder = num_pages_for_size - 1;
  1247.      
  1248.                /********************************************************/
  1249.                /* Set the logical pages for the newly allocated block. */
  1250.                /********************************************************/
  1251.  
  1252.                for (j = start_page_for_remainder; 
  1253.                    (j < NUM_PAGES (best_index_size)); j++)
  1254.                {
  1255.                   directory[0][remainder].
  1256.                      logical_page[j - start_page_for_remainder] =
  1257.                         directory[1][best_indexs_index].logical_page[j];
  1258.                }
  1259.  
  1260.                /*************************************************************/
  1261.                /* Set remainder's index to point to the new leftover piece. */
  1262.                /*************************************************************/
  1263.  
  1264.                directory[0][remainder].offset = 
  1265.                   (best_index_offset + size) % PAGE_SIZE;
  1266.  
  1267.                /*******************/
  1268.                /* Update dir_end. */
  1269.                /*******************/
  1270.  
  1271.                remainders_entry = remainder + page * DIR_ENTRIES_PER_PAGE;
  1272.                if (remainders_entry >= dir_end)
  1273.                   dir_end = remainders_entry + 1;
  1274.  
  1275.                /********************************************************/
  1276.                /* If the leftover piece takes more logical pages than  */
  1277.                /* it should (1 page / PAGE_SIZE) then we need to break */
  1278.                /* the remainder piece into two free blocks.            */
  1279.                /********************************************************/
  1280.  
  1281.                size_mod_page_size = directory[0][remainder].size % PAGE_SIZE;
  1282.                if (size_mod_page_size >
  1283.                       PAGE_SIZE - directory[0][remainder].offset)
  1284.                   status = break_overlap (&remainders_entry); 
  1285.  
  1286.             } /** if status PASSED **/
  1287.  
  1288.          } /** end if directory **/
  1289.  
  1290.       } /** end for remainder = dir_start **/
  1291.  
  1292.       index = 0;
  1293.  
  1294.    } /** end for page **/
  1295.  
  1296.    return (status);
  1297.  
  1298. } /** end split_block() **/
  1299.  
  1300.  
  1301. /*$PAGE*/
  1302. /**********************************************************************/
  1303. /*                                                                    */
  1304. /*     Name:    unsigned int find_new_dir_start (void)                */
  1305. /*                                                                    */
  1306. /*     Description:                                                   */
  1307. /*        This function finds a new starting location in the          */
  1308. /*     directory.  This starting entry is used when looking for a     */
  1309. /*     new block of memory.                                           */
  1310. /*                                                                    */
  1311. /*     Note: We know the new starting location will always start      */
  1312. /*     after the present one except when we free a block.  In this    */
  1313. /*     case, if the freed block's directory entry is before the       */
  1314. /*     current starting entry, we set the starting location to that   */
  1315. /*     of the newly freed block's directory entry.  This is done in   */
  1316. /*     effree().                                                      */
  1317. /*                                                                    */
  1318. /*     Parameters: None                                               */
  1319. /*                                                                    */
  1320. /*     Results returned:                                              */
  1321. /*        PASSED     Operation successful                             */
  1322. /*        error      Non-zero value, see "ERRORS.H" or EMS table A-2  */
  1323. /*                                                                    */
  1324. /*     Calls: map_dir_page()                                          */
  1325. /*                                                                    */
  1326. /*     Called by:  check_best_fit()                                   */
  1327. /*                                                                    */
  1328. /*     Globals referenced/modified: directory                         */
  1329. /*                                  directory_map                     */
  1330. /*                                  dir_page_count                    */
  1331. /*                                  dir_start                         */
  1332. /*                                  dir_end                           */
  1333. /*                                                                    */
  1334. /**********************************************************************/
  1335.  
  1336. unsigned int find_new_dir_start()
  1337. {
  1338.    unsigned int i;                 /* Looping variable                  */
  1339.    unsigned int avail_entry_found; /* An available entry has been found */
  1340.    unsigned int dir_starts_page;   /* Dir_start's dir entry's log page  */
  1341.    unsigned int index;             /* The current index into a page     */
  1342.    unsigned int page;              /* The current dir page mapped in    */
  1343.    unsigned int status;            /* Status of EMM and MEMLIB          */
  1344.  
  1345.    /*******************************/
  1346.    /* Initialize local variables. */
  1347.    /*******************************/
  1348.  
  1349.    avail_entry_found  = FALSE;
  1350.    status = PASSED;
  1351.  
  1352.    /***********************************************************/
  1353.    /* Convert dir_start + 1 to its respective directory page. */
  1354.    /***********************************************************/
  1355.  
  1356.    dir_starts_page = (dir_start + 1) / DIR_ENTRIES_PER_PAGE;
  1357.  
  1358.    /***************************************************************/
  1359.    /* Convert dir_start + 1 to its respective entry's page index. */
  1360.    /* We want to start the first page's index from one after the  */
  1361.    /* current starting location.                                  */
  1362.    /***************************************************************/
  1363.  
  1364.    index = (dir_start + 1) % DIR_ENTRIES_PER_PAGE;
  1365.    
  1366.    /****************************************************************/
  1367.    /* Go through all the directory pages starting with dir_start's */
  1368.    /* page until we find an usable entry.                          */
  1369.    /****************************************************************/
  1370.  
  1371.    for (page = dir_starts_page; ((page < dir_page_count) && 
  1372.                                  (!avail_entry_found) &&
  1373.                                  (status == PASSED)); page++)
  1374.    {
  1375.       /************************************************/
  1376.       /* Map in the directory page specified by page. */
  1377.       /************************************************/
  1378.  
  1379.       status = map_dir_page (page, FIRST_PHYS_PAGE);
  1380.       if (status == PASSED)
  1381.       {
  1382.          /*****************************************************************/
  1383.          /* Go through this page's entries looking for to first available */
  1384.          /* entry.  The first time we enter this loop we start with the   */
  1385.          /* current starting location + 1 (converted to a page's index)   */
  1386.          /* from above.  All other index's after the first page will      */
  1387.          /* start with 0.                                                 */
  1388.          /*****************************************************************/
  1389.  
  1390.          for (i = index; ((i < DIR_ENTRIES_PER_PAGE) && 
  1391.                           (!avail_entry_found)); i++)
  1392.          {
  1393.             if (directory[0][i].token == UNASSIGNED_TOKEN)
  1394.             {
  1395.                /*****************************************/
  1396.                /* Translate the i index into an entry   */
  1397.                /* into the full directory array for the */
  1398.                /* new starting location for dir_start.  */
  1399.                /*****************************************/
  1400.                
  1401.                dir_start = i + page * DIR_ENTRIES_PER_PAGE;
  1402.  
  1403.                /***************************************/
  1404.                /* Make sure the new starting location */
  1405.                /* isn't greater than the end.  If so, */
  1406.                /* than reset dir_end.                 */
  1407.                /***************************************/
  1408.  
  1409.                if (dir_start > dir_end)
  1410.                   dir_end = dir_start + 1;
  1411.                avail_entry_found = TRUE;
  1412.             }
  1413.          } /** end for i **/
  1414.  
  1415.       } /** end if status PASSED **/
  1416.  
  1417.       index = 0;
  1418.  
  1419.    } /** end for page **/
  1420.  
  1421.    return (status);
  1422.  
  1423. } /** end find_new_dir_start() **/
  1424.  
  1425. /*$PAGE*/
  1426. /**********************************************************************/
  1427. /*                                                                    */
  1428. /*     Name:    unsigned int break_overlap (best_index)               */
  1429. /*              unsigned int *best_index;                             */
  1430. /*                                                                    */
  1431. /*     Description:                                                   */
  1432. /*        This function breaks a free block into two parts at a page  */
  1433. /*     boundry.  This is done because check_best_fit() determined     */
  1434. /*     that the requested block would overlap a page boundry          */
  1435. /*     unnecessarily.  For example, we don't want an 8K block using   */
  1436. /*     two logical pages (part of it on one page and the rest on      */
  1437. /*     another).  Suppose we want to allocate a 9K block and          */
  1438. /*     check_best_fit() determined that a 22K block (6K on one page,  */
  1439. /*     16K on the another) was the best fit.  We want to start the 9K */
  1440. /*     block on a page boundry so that it will fit in one logical     */
  1441. /*     page.  This means that we eventually need to split the 22K     */
  1442. /*     block into three pieces:                                       */
  1443. /*                                                                    */
  1444. /*              6K first free piece on the first logical page.        */
  1445. /*              9K allocated piece on the second logical page.        */
  1446. /*              7K free space on the second logical page.             */
  1447. /*                                                                    */
  1448. /*     This routine will do the first split of 6K and 16K.  The       */
  1449. /*     function split_block(), called from efmalloc(), (which does    */
  1450. /*     all the normal splitting) will split the 16K block into its 9K */
  1451. /*     allocated and 7K free pieces.                                  */
  1452. /*                                                                    */
  1453. /*     Parameters:                                                    */
  1454. /*        output  best_index The directory entry of the best fit loc  */
  1455. /*                                                                    */
  1456. /*     Results returned:                                              */
  1457. /*        PASSED     Operation successful                             */
  1458. /*        error      Non-zero value, see "ERRORS.H" or EMS table A-2  */
  1459. /*                                                                    */
  1460. /*     Calls: map_dir_page()                                          */
  1461. /*                                                                    */
  1462. /*     Called by:  efmalloc()                                         */
  1463. /*                 split_block()                                      */
  1464. /*                                                                    */
  1465. /*     Globals referenced/modified: dir_page_count                    */
  1466. /*                                  directory                         */
  1467. /*                                  directory_map                     */
  1468. /*                                  dir_end                           */
  1469. /*                                                                    */
  1470. /**********************************************************************/
  1471.  
  1472. unsigned int break_overlap (best_index)
  1473. unsigned int *best_index;
  1474. {
  1475.    unsigned int i;                 /* Looping variable                  */
  1476.    unsigned int entry_found;       /* Whether an entry was found        */
  1477.    unsigned int free_space;        /* The free space before a page      */
  1478.                                    /* boundry in an overlaping block    */
  1479.    unsigned int new_size;          /* The free space starting on a page */
  1480.                                    /* boundry in an overlaping block    */
  1481.    unsigned int status;            /* Status of EMM and MEMLIB          */
  1482.    unsigned int best_indexs_page;  /* Best_index's dir entry's log page */
  1483.    unsigned int best_indexs_index; /* Best_index's index into its page  */
  1484.    unsigned int page;              /* Current directory page mapped in  */
  1485.    unsigned int index;             /* Index into a directory page       */
  1486.    unsigned int j;                 /* Loop variable                     */
  1487.  
  1488.    status = PASSED;
  1489.  
  1490.    /****************************************************************/
  1491.    /* Check if we need to allocate another page for the directory. */
  1492.    /****************************************************************/
  1493.  
  1494.    if (dir_end >= (unsigned int) (NUM_DIR_ENTRIES (dir_page_count) - 2))
  1495.       status = allocate_new_directory_page();
  1496.  
  1497.    /******************************************************************/
  1498.    /* Convert best_index to its respective directory page and index. */
  1499.    /******************************************************************/
  1500.  
  1501.    best_indexs_page  = *best_index / DIR_ENTRIES_PER_PAGE;
  1502.    best_indexs_index = *best_index % DIR_ENTRIES_PER_PAGE;
  1503.  
  1504.    /*******************************************/
  1505.    /* Map in the best_index's directory page. */
  1506.    /*******************************************/
  1507.  
  1508.    status = map_dir_page (best_indexs_page, FIRST_PHYS_PAGE);
  1509.    if (status == PASSED)
  1510.    {
  1511.       /***************************************/
  1512.       /* Set sizes for breaking the overlap. */
  1513.       /***************************************/
  1514.  
  1515.       free_space = PAGE_SIZE - directory[0][best_indexs_index].offset;
  1516.       new_size   = directory[0][best_indexs_index].size - free_space;
  1517.  
  1518.       /**********************************/
  1519.       /* Initialize variables for loop. */
  1520.       /**********************************/
  1521.  
  1522.       entry_found = FALSE;
  1523.       index       = best_indexs_index;
  1524.  
  1525.       /****************************************************/
  1526.       /* Go through all the directory pages starting with */
  1527.       /* best_index's page until we find an usable entry. */
  1528.       /****************************************************/
  1529.      
  1530.       for (page = best_indexs_page; ((page < dir_page_count) && 
  1531.                                      (!entry_found) &&
  1532.                                      (status == PASSED)); page++)
  1533.       {
  1534.          /************************************************/
  1535.          /* Map in the directory page specified by page. */
  1536.          /************************************************/
  1537.  
  1538.          status = map_dir_page (page, SECOND_PHYS_PAGE);
  1539.          if (status == PASSED)
  1540.          {
  1541.             /********************************************************/
  1542.             /* Go through this page's entries looking for the first */
  1543.             /* available entry.  The first time we enter this loop  */
  1544.             /* we start with best_index's entry (converted to a     */
  1545.             /* page's index from above).  All other index's after   */
  1546.             /* the first page will start with 0.                    */
  1547.             /********************************************************/
  1548.  
  1549.             for (i = index; ((i < DIR_ENTRIES_PER_PAGE) &&
  1550.                                  (!entry_found) &&
  1551.                                  (status == PASSED)); i++)
  1552.             {
  1553.                if ((directory[1][i].token == UNASSIGNED_TOKEN) && 
  1554.                    (directory[1][i].size == 0))
  1555.                {
  1556.                   /********************************************/
  1557.                   /* We found a usable entry.  Convert i to   */ 
  1558.                   /* a full directory entry for best_index.   */
  1559.                   /* Best_index will now point to this        */
  1560.                   /* directory entry though best_indexs_index */
  1561.                   /* and best_indexs_page will still refer to */
  1562.                   /* the original best_index.  Set this       */
  1563.                   /* directory entry to point to the          */
  1564.                   /* allocated block.                         */
  1565.                   /********************************************/
  1566.  
  1567.                   *best_index            = i + (page * DIR_ENTRIES_PER_PAGE);
  1568.                   directory[1][i].token  = *best_index;
  1569.                   directory[1][i].size   = new_size;
  1570.                   directory[1][i].offset = 0;
  1571.  
  1572.                   /*************************************/
  1573.                   /* Set logical pages for this block. */
  1574.                   /*************************************/
  1575.  
  1576.                   for (j = 0; j < NUM_PAGES (new_size); j++)
  1577.                   {
  1578.                      directory[1][i].logical_page[j] =
  1579.                         directory[0][best_indexs_index].logical_page[j + 1];
  1580.                   }
  1581.  
  1582.                   /***********************************/
  1583.                   /* Update size for original block. */
  1584.                   /***********************************/
  1585.  
  1586.                   directory[0][best_indexs_index].size = free_space;
  1587.  
  1588.                   /*****************************/
  1589.                   /* Update dir_end if needed. */
  1590.                   /*****************************/
  1591.  
  1592.                   if (*best_index >= dir_end)
  1593.                      dir_end = *best_index + 1;
  1594.  
  1595.                   entry_found = TRUE;
  1596.  
  1597.                } /** end if directory[1][i] **/
  1598.  
  1599.             } /** end for i **/
  1600.             
  1601.             index = 0;
  1602.  
  1603.          } /** end if status PASSED **/
  1604.  
  1605.       } /** end for page **/
  1606.  
  1607.    } /** end if status PASSED **/
  1608.  
  1609.    return (status);
  1610.  
  1611. } /** done break_overlap() **/
  1612.  
  1613. /*$PAGE*/
  1614. /**********************************************************************/
  1615. /*                                                                    */
  1616. /*     Name:  unsigned int check_best_fit (size, best_index,          */
  1617. /*                                           min_difference)          */
  1618. /*            unsigned int size;                                      */
  1619. /*            unsigned int *best_index;                               */
  1620. /*            long         *min_difference;                           */
  1621. /*                                                                    */
  1622. /*     Description:                                                   */
  1623. /*        This function finds the best fit for a block of memory      */
  1624. /*     asked for in efmalloc().                                       */
  1625. /*                                                                    */
  1626. /*     Parameters:                                                    */
  1627. /*        input    size           The desired size of the block of    */
  1628. /*                                memory.                             */
  1629. /*        output   best_index     The directory entry of the best fit */
  1630. /*        output   min_difference The remainder from best_fit()       */
  1631. /*                                                                    */
  1632. /*     Results returned:                                              */
  1633. /*        PASSED     Operation successful                             */
  1634. /*        error      Non-zero value, see "ERRORS.H" or EMS table A-2  */
  1635. /*                                                                    */
  1636. /*     Calls: allocate_new_directory_page()                           */
  1637. /*            map_dir_page()                                          */
  1638. /*            break_overlap()                                         */
  1639. /*            find_new_dir_start()                                    */
  1640. /*                                                                    */
  1641. /*     Called by: efmalloc()                                          */
  1642. /*                                                                    */
  1643. /*     Globals referenced/modified: dir_page_count                    */
  1644. /*                                  directory                         */
  1645. /*                                  directory_map                     */
  1646. /*                                  dir_start                         */
  1647. /*                                  dir_end                           */
  1648. /*                                                                    */
  1649. /**********************************************************************/
  1650.  
  1651. unsigned int check_best_fit (size, best_index, min_difference)
  1652. unsigned int size;
  1653. unsigned int *best_index;
  1654. long         *min_difference;
  1655. {
  1656.    unsigned int index;                  /* Index into a directory page      */
  1657.    unsigned int status;                 /* Status of EMM and MEMLIB         */
  1658.    unsigned int page;                   /* Directory page to map in         */
  1659.    unsigned int size_mod_page_size;     /* Size of block MOD PAGE_SIZE      */
  1660.    unsigned int free_space;             /* The free space before a page     */
  1661.                                         /* boundry in a free block          */
  1662.    unsigned int dir_starts_page;        /* Dir_start's dir entry's log page */
  1663.    long         this_ones_min_diff;     /* Current block's min difference   */
  1664.    unsigned int this_ones_offset;       /* Current block's offset into a    */
  1665.                                         /* logical page                     */
  1666.    long         new_size;               /* Free space after page boundry    */
  1667.    unsigned int found_exact_fit;        /* Whether we found an exact fit    */
  1668.    unsigned int overlap;                /* Whether we have an overlapping   */
  1669.                                         /* block                            */
  1670.    long         overlap_min_difference; /* Minimum difference for the       */
  1671.                                         /* overlapping block                */
  1672.  
  1673.    /************************************************/
  1674.    /* Initialize variables for best fit algorithm. */
  1675.    /************************************************/
  1676.  
  1677.    index                  = dir_start % DIR_ENTRIES_PER_PAGE;
  1678.    *best_index            = UNASSIGNED_TOKEN;
  1679.    found_exact_fit        = FALSE;
  1680.    overlap                = FALSE;
  1681.    *min_difference        = LARGEST_ALLOCATABLE_BLOCK;
  1682.    status                 = PASSED;
  1683.    overlap_min_difference = LARGEST_ALLOCATABLE_BLOCK;
  1684.    size_mod_page_size     = size % PAGE_SIZE;
  1685.  
  1686.    if (size_mod_page_size == 0)
  1687.       size_mod_page_size = PAGE_SIZE;
  1688.  
  1689.    /**************************************************/
  1690.    /* Make sure a new directory page is allocated    */
  1691.    /* before it is needed.  This done so the a block */
  1692.    /* that has free mem will not be lost to the      */
  1693.    /* the purple zone before a new directory page    */
  1694.    /* is allocated in allocate_new_block().            */
  1695.    /* Allocate_new_directory_page() is called when   */
  1696.    /* the current directory entries is two from      */
  1697.    /* being filled up.                               */
  1698.    /**************************************************/
  1699.  
  1700.    if (dir_end >= (unsigned int) (NUM_DIR_ENTRIES (dir_page_count) - 2))
  1701.       status = allocate_new_directory_page();
  1702.  
  1703.    if (status == PASSED)
  1704.    {
  1705.       dir_starts_page = dir_start / DIR_ENTRIES_PER_PAGE;
  1706.  
  1707.       /*****************************************/
  1708.       /* Go through all of the directory pages */
  1709.       /* until we find an exact fit.           */
  1710.       /*****************************************/
  1711.  
  1712.       for (page = dir_starts_page; ((page < dir_page_count) && 
  1713.                                     (!found_exact_fit) &&
  1714.                                     (status == PASSED)); page++)
  1715.       {
  1716.          /**********************************/
  1717.          /* Map in the this directory page */
  1718.          /**********************************/
  1719.  
  1720.          status = map_dir_page (page, FIRST_PHYS_PAGE);
  1721.          if (status == PASSED)
  1722.          {
  1723.             /*********************************************************/
  1724.             /* Go through the current page looking for the best fit. */
  1725.             /*********************************************************/
  1726.  
  1727.             while ((index < DIR_ENTRIES_PER_PAGE) &&
  1728.                   ((index + page * DIR_ENTRIES_PER_PAGE) <= dir_end) && 
  1729.                   (!found_exact_fit))
  1730.             {  
  1731.                /*****************************************/
  1732.                /* If this block of memory is available. */
  1733.                /*****************************************/
  1734.  
  1735.                if (directory[0][index].token == UNASSIGNED_TOKEN)
  1736.                {
  1737.                   /************************************************/
  1738.                   /* If size is 0 then this block is unallocated. */
  1739.                   /************************************************/
  1740.           
  1741.                   if (directory[0][index].size == 0)
  1742.                   {
  1743.                      /*********************************************/
  1744.                      /* If best_index = UNASSIGNED_TOKEN we       */
  1745.                      /* haven't found any previous blocks to use. */    
  1746.                      /*********************************************/
  1747.               
  1748.                      if (*best_index == UNASSIGNED_TOKEN)
  1749.                          *best_index = index + (page * DIR_ENTRIES_PER_PAGE);
  1750.                   }
  1751.                   else
  1752.                   {
  1753.                      /************************************************/
  1754.                      /* This is a previously freed block and we need */
  1755.                      /* to check how close of a fit it is.           */                          
  1756.                      /************************************************/
  1757.                   
  1758.                      this_ones_min_diff = (long) directory[0][index].size - size;
  1759.                      if ((this_ones_min_diff >= 0) &&
  1760.                         (this_ones_min_diff < *min_difference))
  1761.                      {
  1762.                         /**************************************/
  1763.                         /* If exact fit then take this block. */
  1764.                         /**************************************/
  1765.    
  1766.                         if (this_ones_min_diff == 0)
  1767.                         {
  1768.                            found_exact_fit = TRUE;
  1769.                            *best_index     = index + (page * DIR_ENTRIES_PER_PAGE);
  1770.                            *min_difference = 0;
  1771.                            overlap         = FALSE;
  1772.                         }
  1773.                         else
  1774.                         {
  1775.                            /***********************************************/
  1776.                            /* Make sure that putting the newly allocated  */
  1777.                            /* block at the beginning of the free block    */
  1778.                            /* won't cause the new block to overlap more   */
  1779.                            /* logical pages than it needs.                */
  1780.                            /*                                             */
  1781.                            /* If the remainder of the requested block     */
  1782.                            /* size MOD PAGE_SIZE will fit in the first    */
  1783.                            /* logical page of the freed block, then the   */
  1784.                            /* requested block will fit correctly.         */
  1785.                            /***********************************************/
  1786.    
  1787.                            /*******************************************/
  1788.                            /* Where this free block starts within its */
  1789.                            /* first logical page.                     */
  1790.                            /*******************************************/
  1791.  
  1792.                            this_ones_offset = directory[0][index].offset;
  1793.  
  1794.                            /********************************************/
  1795.                            /* The room left on the first logical page. */
  1796.                            /********************************************/
  1797.  
  1798.                            free_space = PAGE_SIZE - this_ones_offset;
  1799.  
  1800.                            if (free_space >= size_mod_page_size)
  1801.                            {
  1802.                               /******************************************/
  1803.                               /* The block will fit just fine.  We will */
  1804.                               /* have the block itself and a remainder. */
  1805.                               /******************************************/
  1806.  
  1807.                               *best_index     = index + (page * DIR_ENTRIES_PER_PAGE);
  1808.                               *min_difference = this_ones_min_diff;
  1809.                               overlap         = FALSE;
  1810.                            }
  1811.                            else        
  1812.                            {
  1813.                               /********************************************/
  1814.                               /* The new block will fit but we have to    */
  1815.                               /* start it on this free block's first page */
  1816.                               /* boundry.  We will need to keep track of  */
  1817.                               /* the space before the page boundry, the   */
  1818.                               /* new block, and any remainder from the    */
  1819.                               /* new block.  We will have an overlap to   */
  1820.                               /* break.                                   */
  1821.                               /********************************************/
  1822.  
  1823.                               new_size = (long) directory[0][index].size - free_space;
  1824.                               if (new_size >= size)
  1825.                               {
  1826.                                  overlap = TRUE;
  1827.                                  this_ones_min_diff = new_size - size;
  1828.                                  if (this_ones_min_diff < overlap_min_difference)
  1829.                                  {
  1830.                                     overlap_min_difference = new_size - size;
  1831.                                     *best_index = index + (page * DIR_ENTRIES_PER_PAGE);
  1832.                                  }
  1833.                               }
  1834.                            } /** end else **/
  1835.  
  1836.                         } /** end else **/ 
  1837.  
  1838.                      } /** end if temp_difference ... **/
  1839.  
  1840.                   } /** end else **/
  1841.  
  1842.                } /** end if directory **/
  1843.  
  1844.                index++;
  1845.  
  1846.             } /** end while **/
  1847.  
  1848.          } /** end if passed **/
  1849.          index = 0;
  1850.  
  1851.       } /** end if page **/
  1852.  
  1853.       /**********************************************/
  1854.       /* If we have an overlap we need to break it. */
  1855.       /**********************************************/
  1856.  
  1857.       if ((overlap) && 
  1858.           (status == PASSED))
  1859.       {
  1860.          *min_difference = overlap_min_difference;
  1861.          status = break_overlap (best_index);
  1862.       }
  1863.  
  1864.       /****************************************************/
  1865.       /* Update our starting entry if the current one ==  */
  1866.       /* to best_index and we don't have an overlap.      */
  1867.       /****************************************************/
  1868.  
  1869.       if ((dir_start == *best_index) && 
  1870.           (!overlap) && 
  1871.           (status == PASSED))
  1872.          status = find_new_dir_start();
  1873.  
  1874.       /**************************************/
  1875.       /* Update our ending entry if needed. */
  1876.       /**************************************/
  1877.  
  1878.       if ((*best_index >= dir_end) && 
  1879.           (status == PASSED))
  1880.          dir_end = *best_index + 1;
  1881.  
  1882.    } /** end if passed **/
  1883.  
  1884.    return (status);
  1885.  
  1886. } /* end check_best_fit() */
  1887.  
  1888. /*$PAGE*/
  1889. /**********************************************************************/
  1890. /*                                                                    */
  1891. /*     Name: unsigned int check_if_all_blocks_free (all_blocks_free)  */
  1892. /*           unsigned int *all_blocks_free;                           */
  1893. /*                                                                    */
  1894. /*     Description:                                                   */
  1895. /*        If the block being freed by effree() is the last one to be  */
  1896. /*     freed then we need to deallocate all the pages allocated to    */
  1897. /*     this application.  This tells us that the program using MEMLIB */
  1898. /*     may be terminating and we want to be sure that all pages for   */
  1899. /*     this application have been deallocated.  This function will    */
  1900. /*     see if there are any blocks left in the directory that are     */
  1901. /*     allocated and if not, will deallocate all pages that this      */
  1902. /*     application owns.                                              */
  1903. /*                                                                    */
  1904. /*     Parameters:                                                    */
  1905. /*        output  free_status     TRUE - all blocks are free          */
  1906. /*                                FALSE - there are some blocks used  */
  1907. /*                                                                    */
  1908. /*     Results returned:                                              */
  1909. /*        PASSED    Operation successful                              */
  1910. /*        error     Non-zero value, see "ERRORS.H" or EMS table A-2   */
  1911. /*                                                                    */
  1912. /*     Calls: map_dir_page()                                          */
  1913. /*                                                                    */
  1914. /*     Called by: effree()                                            */
  1915. /*                                                                    */
  1916. /*     Globals referenced/modified: dir_page_count                    */
  1917. /*                                  directory                         */
  1918. /*                                  directory_map                     */
  1919. /*                                                                    */
  1920. /**********************************************************************/
  1921.  
  1922. unsigned int check_if_all_blocks_free (all_blocks_free)
  1923. unsigned int *all_blocks_free;
  1924. {
  1925.    unsigned int status;       /* Status of EMM and MEMLIB          */
  1926.    unsigned int page;         /* Current directory page mapped in  */
  1927.    unsigned int index;        /* Current index into a logical page */
  1928.  
  1929.    /******************************/
  1930.    /* Assume all blocks are free */
  1931.    /* and status OK.             */
  1932.    /******************************/
  1933.  
  1934.    *all_blocks_free = TRUE;
  1935.    status           = PASSED;
  1936.  
  1937.    /**************************************************************/
  1938.    /* Loop through the directory, checking for non-freed blocks. */
  1939.    /**************************************************************/
  1940.  
  1941.    for (page = 0; ((page < dir_page_count) &&
  1942.                    (*all_blocks_free) &&
  1943.                    (status == PASSED)); page++)
  1944.    {
  1945.       /*******************************/
  1946.       /* Map in this directory page. */
  1947.       /*******************************/
  1948.  
  1949.       status = map_dir_page (page, FIRST_PHYS_PAGE);
  1950.       if (status == PASSED)
  1951.       {
  1952.          /************************************/
  1953.          /* Check all index's for this page. */
  1954.          /************************************/
  1955.  
  1956.          for (index = 0; ((index < DIR_ENTRIES_PER_PAGE) &&
  1957.                           (*all_blocks_free)); index++)
  1958.          {
  1959.             if (directory[0][index].token != UNASSIGNED_TOKEN)
  1960.             {
  1961.                /**********************************************/
  1962.                /* If we find a block that's being used, set  */
  1963.                /* all_block_free to FALSE and stop checking. */
  1964.                /**********************************************/
  1965.  
  1966.                *all_blocks_free = FALSE;
  1967.             }
  1968.          } /** end for index **/
  1969.  
  1970.       } /** end if status PASSED **/
  1971.  
  1972.    } /** end for page **/
  1973.  
  1974.    return (status);
  1975.  
  1976. }  /** end if_all_blocks_free **/
  1977.  
  1978.  
  1979. /*$PAGE*/
  1980. /**********************************************************************/
  1981. /*                                                                    */
  1982. /*     Name:  unsigned int coalesce_block (block1, block2, coalasce)  */
  1983. /*            unsigned int block1;                                    */
  1984. /*            unsigned int block2;                                    */
  1985. /*            unsigned int *coalesce;                                 */
  1986. /*                                                                    */
  1987. /*     Description:                                                   */
  1988. /*        This coalesces one block of free expanded memory (block1)   */
  1989. /*     to another (block2).                                           */
  1990. /*                                                                    */
  1991. /*     Parameters:                                                    */
  1992. /*        input    block1      The identifier for the first block.    */
  1993. /*                 block2      The identifier for the second block.   */
  1994. /*         output  coalesce    Whether we really coalesced or not.    */
  1995. /*                                                                    */
  1996. /*     Results returned:                                              */
  1997. /*        PASSED     Coalescing successful or not needed              */
  1998. /*        error      Non-zero value, see "ERRORS.H" or EMS table A-2  */
  1999. /*                                                                    */
  2000. /*     Calls: map_dir_page()                                          */
  2001. /*            get_context()                                           */
  2002. /*            set_context()                                           */
  2003. /*                                                                    */
  2004. /*     Called by:  search_before()                                    */
  2005. /*                 search_after()                                     */
  2006. /*                                                                    */
  2007. /*     Globals referenced/modified: directory                         */
  2008. /*                                  directory_map                     */
  2009. /*                                                                    */
  2010. /**********************************************************************/
  2011.  
  2012. unsigned int coalesce_block (block1, block2, coalesce)
  2013. unsigned int block1;
  2014. unsigned int block2;
  2015. unsigned int *coalesce;
  2016. {
  2017.    unsigned int   j;              /* Looping variable                     */
  2018.    unsigned int   block1s_page;   /* Block1's directory entry's log page  */
  2019.    unsigned int   block1s_index;  /* Block1's index into its logical page */
  2020.    unsigned int   block2s_page;   /* Block2's directory entry's log page  */
  2021.    unsigned int   block2s_index;  /* Block2's index into its logical page */
  2022.    unsigned int   end_of_block2;  /* End of block2 (size+offset)          */
  2023.    unsigned int   start_page;     /* Starting logical page for coalescing */
  2024.    unsigned int   status;         /* Status of EMM and MEMLIB             */
  2025.    CONTEXT_STRUCT context;        /* For storing the current context      */
  2026.  
  2027.    /******************************************************************/
  2028.    /* We need to continue where we left off from when we return      */
  2029.    /* to search_before() or search_after(), so we need to save       */
  2030.    /* the pages they had mapped in before they called this function. */
  2031.    /******************************************************************/
  2032.  
  2033.    status = get_context (&context);
  2034.    if (status == PASSED)
  2035.    {
  2036.       /**************************************************************/
  2037.       /* Convert block1 to its respective directory page and index. */
  2038.       /**************************************************************/
  2039.  
  2040.       block1s_page  = block1 / DIR_ENTRIES_PER_PAGE;
  2041.       block1s_index = block1 % DIR_ENTRIES_PER_PAGE;
  2042.  
  2043.       /***********************************/
  2044.       /* Map in block1's directory page. */
  2045.       /***********************************/
  2046.  
  2047.       status = map_dir_page (block1s_page, FIRST_PHYS_PAGE);
  2048.    }
  2049.  
  2050.    if (status == PASSED)
  2051.    {
  2052.       /*********************************************************/
  2053.       /* Convert block1 to its respective directory page and   */
  2054.       /* index.  We're going to map this page into the second  */
  2055.       /* physical page.  In order to access this pages entries */
  2056.       /* we need to offset its indexes by DIR_ENTRIES_PER_PAGE */
  2057.       /* from the beginning of the first physical page.        */
  2058.       /*********************************************************/
  2059.  
  2060.       block2s_page  = block2 / DIR_ENTRIES_PER_PAGE;
  2061.       block2s_index = block2 % DIR_ENTRIES_PER_PAGE;
  2062.  
  2063.       /*****************************************************/
  2064.       /* Map in block2's directory page using the          */
  2065.       /* directory_map's second array element to map this  */
  2066.       /* page in at physical page one while keeping        */
  2067.       /* block1's  directory page at physical page zero.   */
  2068.       /*****************************************************/
  2069.  
  2070.       status = map_dir_page (block2s_page, SECOND_PHYS_PAGE);
  2071.  
  2072.       /****************************/
  2073.       /* Coalesce the two blocks. */
  2074.       /****************************/
  2075.  
  2076.       if (status == PASSED)
  2077.       {
  2078.          /****************************************/
  2079.          /* Assume we will coalesce these blocks */
  2080.          /****************************************/
  2081.  
  2082.          *coalesce = TRUE;
  2083.  
  2084.          /*********************************************/
  2085.          /* Set the starting logical page for block2. */
  2086.          /*********************************************/
  2087.  
  2088.          end_of_block2 = (directory[1][block2s_index].offset +
  2089.                           directory[1][block2s_index].size) % PAGE_SIZE;
  2090.  
  2091.          if (end_of_block2 == 0)
  2092.             start_page = NUM_PAGES (directory[1][block2s_index].size);
  2093.          else
  2094.             start_page = NUM_PAGES (directory[1][block2s_index].size) - 1;
  2095.  
  2096.          /********************************************************/
  2097.          /* If combining the blocks would cause too many logical */
  2098.          /* pages to be used, DON'T coalesce them.               */
  2099.          /********************************************************/
  2100.  
  2101.          if ((start_page + NUM_PAGES (directory[0][block1s_index].size))
  2102.              >= MAX_ALLOCATABLE_PAGES)
  2103.             *coalesce = FALSE;
  2104.  
  2105.          if (*coalesce)
  2106.          {
  2107.  
  2108.             /*****************************************************/
  2109.             /* Combine the logical pages for block1 into block2. */
  2110.             /*****************************************************/
  2111.  
  2112.             for (j = 0; j < NUM_PAGES (directory[0][block1s_index].size); j++)
  2113.             {
  2114.                directory[1][block2s_index].logical_page[start_page + j] =
  2115.                   directory[0][block1s_index].logical_page[j];
  2116.             }
  2117.  
  2118.             /******************************************/
  2119.             /* Set block2's size to the combined size */
  2120.             /* and zero out block 1.                  */
  2121.             /******************************************/
  2122.  
  2123.             directory[1][block2s_index].size += directory[0][block1s_index].size;
  2124.             directory[0][block1s_index].size = 0;
  2125.  
  2126.          }
  2127.       }
  2128.    }
  2129.  
  2130.    /************************************/
  2131.    /* Restore the pages that were here */
  2132.    /* before this function was called. */
  2133.    /************************************/
  2134.  
  2135.    if (status == PASSED)
  2136.       status = set_context (&context);
  2137.  
  2138.    return (status);
  2139.  
  2140. } /** end coalesce_block() **/
  2141.  
  2142. /*$PAGE*/
  2143. /**********************************************************************/
  2144. /*                                                                    */
  2145. /*     Name:  unsigned int search_after (token, final_entry,          */
  2146. /*                                         usable_entry)              */
  2147. /*            unsigned int token;                                     */
  2148. /*            unsigned int *final_entry;                              */
  2149. /*            unsigned int *usable_entry;                             */
  2150. /*                                                                    */
  2151. /*     Description:                                                   */
  2152. /*        This function searches for a free block of memory after the */
  2153. /*     block of memory we just freed.  This is done in order to       */
  2154. /*     coalesce the two blocks.                                       */
  2155. /*                                                                    */
  2156. /*     Parameters:                                                    */
  2157. /*        input   token        The token of the block of memory       */
  2158. /*                             that's been freed                      */
  2159. /*        output  final_entry  The directory entry of the final       */
  2160. /*                             coalesced block or unassigned if no    */
  2161. /*                             blocks were found.                     */
  2162. /*                usable_entry The directory entry of a usable block  */
  2163. /*                                                                    */
  2164. /*     Results returned:                                              */
  2165. /*        PASSED     Operation successful                             */
  2166. /*        error      Non-zero value, see "ERRORS.H" or EMS table A-2  */
  2167. /*                                                                    */
  2168. /*     Calls: coalesce_block()                                        */
  2169. /*            map_dir_page()                                          */
  2170. /*                                                                    */
  2171. /*     Called by: effree()                                            */
  2172. /*                                                                    */
  2173. /*     Globals referenced/modified: directory                         */
  2174. /*                                  directory_map                     */
  2175. /*                                  dir_page_count                    */
  2176. /*                                                                    */
  2177. /**********************************************************************/
  2178.  
  2179. unsigned int search_after (token, final_entry, usable_entry)
  2180. unsigned int token;
  2181. unsigned int *final_entry;
  2182. unsigned int *usable_entry;
  2183. {
  2184.    unsigned int index;              /* Index into a directory page         */
  2185.    unsigned int indexs_entry;       /* Index translated to a full dir entry*/
  2186.    unsigned int coalesce;           /* Whether we should coalesce or not   */
  2187.    unsigned int tokens_last_page;   /* Last logical page for token's block */
  2188.    unsigned int end_of_tokens_block;/* The end of token's block            */
  2189.    unsigned int page;               /* Directory pages to loop through     */
  2190.    unsigned int tokens_page;        /* Token's directory entry's log page  */
  2191.    unsigned int tokens_index;       /* Token's index into its logical page */
  2192.    unsigned int status;             /* Status of EMM and MEMLIB            */
  2193.  
  2194.    /****************************************************************/
  2195.    /* Convert the token passed in to its respective directory page */
  2196.    /* and index.  We're going to map this page into the second     */
  2197.    /* physical page.  In order to access this pages entries we     */
  2198.    /* need to use second_dir_page.                                 */    
  2199.    /****************************************************************/
  2200.  
  2201.    tokens_page  = token / DIR_ENTRIES_PER_PAGE;
  2202.    tokens_index = token % DIR_ENTRIES_PER_PAGE;
  2203.  
  2204.    /*********************************************************/
  2205.    /* Map in the token's directory page using the           */
  2206.    /* directory_map's second array element to map this page */
  2207.    /* in at physical page one while keeping the block to be */
  2208.    /* coalesced's directory page at physical page zero.     */
  2209.    /*********************************************************/
  2210.  
  2211.    status = map_dir_page (tokens_page, SECOND_PHYS_PAGE);
  2212.    if (status == PASSED)
  2213.    {
  2214.       /**********************************/
  2215.       /* Find the end of token's block. */
  2216.       /**********************************/
  2217.  
  2218.       end_of_tokens_block = (directory[1][tokens_index].size + 
  2219.                              directory[1][tokens_index].offset) % PAGE_SIZE;
  2220.  
  2221.       /**************************/
  2222.       /* Set variables for loop */
  2223.       /**************************/
  2224.  
  2225.       *final_entry     = UNASSIGNED_TOKEN;
  2226.       tokens_last_page = NUM_PAGES (directory[1][tokens_index].size) - 1;
  2227.       coalesce         = FALSE;
  2228.  
  2229.       /******************************************************/
  2230.       /* Search for a free block of memory after this block */
  2231.       /* to coalesce into one free block.                   */
  2232.       /******************************************************/
  2233.  
  2234.       for (page = 0; ((page < dir_page_count) &&
  2235.                       (status == PASSED) && 
  2236.                       (!coalesce)); page++)
  2237.       {
  2238.          /*******************************/
  2239.          /* Map in this directory page. */
  2240.          /*******************************/
  2241.  
  2242.          status = map_dir_page (page, FIRST_PHYS_PAGE);
  2243.          /*********************************************/
  2244.          /* Go through all the indexes for this page. */
  2245.          /*********************************************/
  2246.  
  2247.          for (index = 0; ((index < DIR_ENTRIES_PER_PAGE) &&
  2248.                           (status == PASSED) && 
  2249.                           (!coalesce)); index++)
  2250.          {
  2251.             /********************************************/
  2252.             /* Convert index to a full directory entry. */
  2253.             /********************************************/
  2254.  
  2255.             indexs_entry = index + page * DIR_ENTRIES_PER_PAGE;
  2256.  
  2257.             /*********************************************************/
  2258.             /* For index's block test:                               */
  2259.             /* Is it free?                                           */
  2260.             /* Is it > 0?                                            */
  2261.             /* Is it different than the block we called effree with? */
  2262.             /* Would its size make a coalesced block > 64K?          */
  2263.             /*********************************************************/
  2264.             
  2265.             if ((directory[0][index].token == UNASSIGNED_TOKEN) && 
  2266.                 (directory[0][index].size > 0) &&
  2267.                 (indexs_entry != token) && 
  2268.                 ((unsigned long) directory[0][index].size + 
  2269.                  directory[1][tokens_index].size < K64K))
  2270.             {
  2271.                /****************************************************/
  2272.                /* If the end of token's block equals the beginning */
  2273.                /* of index's block then index's block could lie    */
  2274.                /* AFTER our block.                                 */
  2275.                /****************************************************/
  2276.  
  2277.                if (end_of_tokens_block == directory[0][index].offset)
  2278.                {
  2279.                   /******************************************************/
  2280.                   /* Test the logical pages for these two blocks to     */
  2281.                   /* see if we want to coalesce them.  We will coalesce */
  2282.                   /* if either of the following is true:                */
  2283.                   /*                                                    */
  2284.                   /* 1. If the token's block ends on an exact page      */
  2285.                   /*    boundry (end_of_tokens_block == 0) then we do   */
  2286.                   /*    NOT want the last logical page of token's block */
  2287.                   /*    to match the first logical page of index's      */
  2288.                   /*    block.                                          */
  2289.                   /*                                                    */
  2290.                   /* 2. If token's block ends in the middle of a        */
  2291.                   /*    logical page (end_of_tokens_block != 0) the we  */
  2292.                   /*    DO want token's block's last logical page to    */
  2293.                   /*    match index's block's first logical page.       */
  2294.                   /******************************************************/
  2295.  
  2296.                   if (end_of_tokens_block == 0)
  2297.                   {
  2298.                      if (directory[1][tokens_index].logical_page[tokens_last_page] 
  2299.                           != directory[0][index].logical_page[0])
  2300.                      {
  2301.                         coalesce = TRUE;
  2302.                      }
  2303.                   }
  2304.                   else 
  2305.                   {
  2306.                      if (directory[1][tokens_index].logical_page[tokens_last_page] 
  2307.                           == directory[0][index].logical_page[0])
  2308.                      {
  2309.                         coalesce = TRUE;
  2310.                      }
  2311.                   }
  2312.                   if (coalesce)
  2313.                   {
  2314.                      /************************************/
  2315.                      /* We've got a winner! Coalesce the */
  2316.                      /* i'th block into our block.       */
  2317.                      /************************************/
  2318.  
  2319.                      status = coalesce_block (indexs_entry, token, &coalesce);
  2320.  
  2321.                      if ((status == PASSED) && coalesce)
  2322.                      {
  2323.                         *final_entry  = token;
  2324.                         *usable_entry = indexs_entry;
  2325.                      }
  2326.  
  2327.                   } /** end if coalesce **/
  2328.  
  2329.                } /** end if end_of_tokens_block **/
  2330.  
  2331.             }  /** end if directory **/
  2332.  
  2333.          }  /** end for index **/
  2334.  
  2335.       }  /** end for page **/
  2336.  
  2337.    } /** end if PASSED **/
  2338.    
  2339.    return (status);
  2340.  
  2341. } /** end search_after() **/
  2342.  
  2343. /*$PAGE*/
  2344. /**********************************************************************/
  2345. /*                                                                    */
  2346. /*     Name:  unsigned int search_before (token, final_entry,         */
  2347. /*                                          usable_entry)             */
  2348. /*            unsigned int token;                                     */
  2349. /*            unsigned int *final_entry;                              */
  2350. /*            unsigned int *usable_entry;                             */
  2351. /*                                                                    */
  2352. /*     Description:                                                   */
  2353. /*        This function searches for a free block of memory before    */
  2354. /*     the block of memory we just freed.  This is done in order to   */
  2355. /*     coalesce the two blocks.                                       */
  2356. /*                                                                    */
  2357. /*     Parameters:                                                    */
  2358. /*        input   token        The token of the block of memory       */
  2359. /*                             that's been freed                      */
  2360. /*        output  final_entry  The directory entry of the final       */
  2361. /*                             coalesced block or unassigned if no    */
  2362. /*                             blocks were found.                     */
  2363. /*                temp_entry   The directory entry of a usable block  */
  2364. /*                                                                    */
  2365. /*     Results returned:                                              */
  2366. /*        PASSED     Operation successful                             */
  2367. /*        error      Non-zero value, see "ERRORS.H" or EMS table A-2  */
  2368. /*                                                                    */
  2369. /*     Calls: coalesce_block()                                        */
  2370. /*            map_dir_page()                                          */
  2371. /*                                                                    */
  2372. /*     Called by: effree()                                            */
  2373. /*                                                                    */
  2374. /*     Globals referenced/modified: directory                         */
  2375. /*                                  directory_map                     */
  2376. /*                                  dir_page_count                    */
  2377. /*                                                                    */
  2378. /**********************************************************************/
  2379.  
  2380. unsigned int search_before (token, final_entry, usable_entry)
  2381. unsigned int token;
  2382. unsigned int *final_entry;
  2383. unsigned int *usable_entry;
  2384. {
  2385.    unsigned int index;              /* Index into a directory page          */
  2386.    unsigned int indexs_entry;       /* Index translated to a full dir entry */
  2387.    unsigned int indexs_last_page;   /* Last logical page for index's block  */
  2388.    unsigned int coalesce;           /* Whether we should coalesce or not    */
  2389.    unsigned int end_of_indexs_block;/* The end of token's block             */
  2390.    unsigned int page;               /* Directory pages to loop through      */
  2391.    unsigned int tokens_page;        /* Token's directory entry's log page   */
  2392.    unsigned int tokens_index;       /* Token's index into its logical page  */
  2393.    unsigned int status;             /* Status of EMM and MEMLIB             */
  2394.  
  2395.    /****************************************************************/
  2396.    /* Convert the token passed in to its respective directory page */
  2397.    /* and index.  We're going to map this page into the second     */
  2398.    /* physical page.  In order to access this page's entries we    */
  2399.    /* need to use directory[1].                                    */
  2400.    /****************************************************************/
  2401.  
  2402.    tokens_page  = token / DIR_ENTRIES_PER_PAGE;
  2403.    tokens_index = token % DIR_ENTRIES_PER_PAGE;
  2404.  
  2405.    /*********************************************************/
  2406.    /* Map in the token's directory page using the           */
  2407.    /* directory_map's second array element to map this page */
  2408.    /* in at physical page one while keeping the block to be */
  2409.    /* coalesced's directory page at physical page zero.     */
  2410.    /*********************************************************/
  2411.  
  2412.    status = map_dir_page (tokens_page, SECOND_PHYS_PAGE);
  2413.    if (status == PASSED)
  2414.    {
  2415.       /***************************/
  2416.       /* Set variables for loop. */
  2417.       /***************************/
  2418.  
  2419.       coalesce = FALSE;
  2420.  
  2421.       /*************************************************/
  2422.       /* Search for a free block of memory before this */
  2423.       /* block to coalesce into one free block.        */
  2424.       /*************************************************/
  2425.  
  2426.       for (page = 0; ((page < dir_page_count) &&
  2427.                       (status == PASSED) && 
  2428.                       (!coalesce)); page++)
  2429.       {
  2430.          /*******************************/
  2431.          /* Map in this directory page. */
  2432.          /*******************************/
  2433.  
  2434.          status = map_dir_page (page, FIRST_PHYS_PAGE);
  2435.  
  2436.          /*********************************************/
  2437.          /* Go through all the indexes for this page. */
  2438.          /*********************************************/
  2439.  
  2440.          for (index = 0; ((index < DIR_ENTRIES_PER_PAGE) &&
  2441.                        (status == PASSED) &&
  2442.                        (!coalesce)); index++)
  2443.          {
  2444.             /********************************************/
  2445.             /* Convert index to a full directory entry. */
  2446.             /********************************************/
  2447.  
  2448.             indexs_entry = index + page * DIR_ENTRIES_PER_PAGE;
  2449.  
  2450.             /*********************************************************/
  2451.             /* For index's block test:                               */
  2452.             /* Is it free?                                           */
  2453.             /* Is it > 0?                                            */
  2454.             /* Is it different than the block we called effree with? */
  2455.             /* Would its size make a coalesced block > 64K?          */
  2456.             /*********************************************************/
  2457.             
  2458.             if ((directory[0][index].token == UNASSIGNED_TOKEN) && 
  2459.                 (directory[0][index].size > 0) &&
  2460.                 (indexs_entry != token) && 
  2461.                 ((unsigned long) directory[0][index].size + 
  2462.                  directory[1][tokens_index].size < K64K))
  2463.             {
  2464.                end_of_indexs_block = (directory[0][index].offset +
  2465.                                       directory[0][index].size) % PAGE_SIZE;
  2466.  
  2467.                indexs_last_page = NUM_PAGES (directory[0][index].size) - 1;
  2468.  
  2469.  
  2470.                /*********************************************/
  2471.                /* If the beginning of token's block exactly */
  2472.                /* matches the end of index's block then     */
  2473.                /* index's block could lie BEFORE our block. */
  2474.                /*********************************************/
  2475.  
  2476.                if (directory[1][tokens_index].offset == end_of_indexs_block)
  2477.                {
  2478.                   /******************************************************/
  2479.                   /* Test the logical pages for these two blocks to     */
  2480.                   /* see if we want to coalesce them.  We will coalesce */
  2481.                   /* if either of the following is true:                */
  2482.                   /*                                                    */
  2483.                   /* 1. If the token's block ends on an exact page      */
  2484.                   /*    boundry (end_of_indexs_block == 0) then we do   */
  2485.                   /*    NOT want the first logical page of token's      */
  2486.                   /*    block to match the last logical page of index's */
  2487.                   /*    block.                                          */
  2488.                   /*                                                    */
  2489.                   /* 2. If token's block ends in the middle of a        */
  2490.                   /*    logical page (end_of_indexs_block != 0) the we  */
  2491.                   /*    DO want token's block's first logical page to   */
  2492.                   /*    match index's block's last logical page.        */
  2493.                   /******************************************************/
  2494.  
  2495.                   if (end_of_indexs_block == 0)
  2496.                   {
  2497.                      if (directory[0][index].logical_page[indexs_last_page] !=
  2498.                          directory[1][tokens_index].logical_page[0])
  2499.                      {
  2500.                         coalesce   = TRUE;
  2501.                      }
  2502.                   }
  2503.                   else 
  2504.                   {
  2505.                      if (directory[0][index].logical_page[indexs_last_page] ==
  2506.                             directory[1][tokens_index].logical_page[0])
  2507.                      {
  2508.                         coalesce   = TRUE;
  2509.                      }
  2510.                   }
  2511.                   if (coalesce)
  2512.                   {
  2513.                      /************************************/
  2514.                      /* We've got a winner! Coalesce the */
  2515.                      /* i'th block into our block.       */
  2516.                      /************************************/
  2517.  
  2518.                      status = coalesce_block (token, indexs_entry, &coalesce);
  2519.  
  2520.                      if ((status == PASSED) && 
  2521.                          coalesce)
  2522.                      {
  2523.                         *final_entry  = indexs_entry;
  2524.                         *usable_entry = token;
  2525.                      }
  2526.  
  2527.                   } /** end if coalesce **/
  2528.  
  2529.                } /** end if directory **/
  2530.  
  2531.             }  /** end if directory **/
  2532.  
  2533.          }  /** end for index = 0 **/
  2534.  
  2535.       }  /** end for page **/
  2536.  
  2537.    } /** end if PASSED **/
  2538.  
  2539.    return (status);
  2540. }  /** end search_before() **/
  2541.  
  2542.  
  2543.  
  2544.  
  2545.  
  2546.